// controls.js - Zoom, rotate and toggle controls

import { CONFIG, EARTH_CONFIG } from "./constants.js";
import { updateZoomDisplay, showStatusMessage } from "./ui.js";
import { toggleTerrain } from "./earth.js";
import { reloadData, clearLockedObject } from "./main.js";
import {
  toggleSatellites,
  toggleTrails,
  getShowSatellites,
  getSatelliteCount,
} from "./satellites.js";
import { toggleCables, getShowCables } from "./cables.js";

export let autoRotate = true;
export let zoomLevel = 1.0;
export let showTerrain = false;
export let isDragging = false;
export let layoutExpanded = false;

let earthObj = null;
let listeners = [];
let cleanupFns = [];

function bindListener(element, eventName, handler, options) {
  if (!element) return;
  element.addEventListener(eventName, handler, options);
  listeners.push(() =>
    element.removeEventListener(eventName, handler, options),
  );
}

function resetCleanup() {
  cleanupFns.forEach((cleanup) => cleanup());
  cleanupFns = [];
  listeners.forEach((cleanup) => cleanup());
  listeners = [];
}

export function setupControls(camera, renderer, scene, earth) {
  resetCleanup();
  earthObj = earth;
  setupZoomControls(camera);
  setupWheelZoom(camera, renderer);
  setupRotateControls(camera, earth);
  setupTerrainControls();
  setupLiquidGlassInteractions();
}

function setupZoomControls(camera) {
  let zoomInterval = null;
  let holdTimeout = null;
  let startTime = 0;
  const HOLD_THRESHOLD = 150;
  const LONG_PRESS_TICK = 50;
  const CLICK_STEP = 10;

  const MIN_PERCENT = CONFIG.minZoom * 100;
  const MAX_PERCENT = CONFIG.maxZoom * 100;

  function doZoomStep(direction) {
    let currentPercent = Math.round(zoomLevel * 100);
    let newPercent =
      direction > 0 ? currentPercent + CLICK_STEP : currentPercent - CLICK_STEP;

    if (newPercent > MAX_PERCENT) newPercent = MAX_PERCENT;
    if (newPercent < MIN_PERCENT) newPercent = MIN_PERCENT;

    zoomLevel = newPercent / 100;
    applyZoom(camera);
  }

  function doContinuousZoom(direction) {
    let currentPercent = Math.round(zoomLevel * 100);
    let newPercent = direction > 0 ? currentPercent + 1 : currentPercent - 1;

    if (newPercent > MAX_PERCENT) newPercent = MAX_PERCENT;
    if (newPercent < MIN_PERCENT) newPercent = MIN_PERCENT;

    zoomLevel = newPercent / 100;
    applyZoom(camera);
  }

  function startContinuousZoom(direction) {
    doContinuousZoom(direction);
    zoomInterval = window.setInterval(() => {
      doContinuousZoom(direction);
    }, LONG_PRESS_TICK);
  }

  function stopZoom() {
    if (zoomInterval) {
      clearInterval(zoomInterval);
      zoomInterval = null;
    }
    if (holdTimeout) {
      clearTimeout(holdTimeout);
      holdTimeout = null;
    }
  }

  function handleMouseDown(direction) {
    startTime = Date.now();
    stopZoom();
    holdTimeout = window.setTimeout(() => {
      startContinuousZoom(direction);
    }, HOLD_THRESHOLD);
  }

  function handleMouseUp(direction) {
    const heldTime = Date.now() - startTime;
    stopZoom();
    if (heldTime < HOLD_THRESHOLD) {
      doZoomStep(direction);
    }
  }

  cleanupFns.push(stopZoom);

  const zoomIn = document.getElementById("zoom-in");
  const zoomOut = document.getElementById("zoom-out");
  const zoomValue = document.getElementById("zoom-value");

  bindListener(zoomIn, "mousedown", () => handleMouseDown(1));
  bindListener(zoomIn, "mouseup", () => handleMouseUp(1));
  bindListener(zoomIn, "mouseleave", stopZoom);
  bindListener(zoomIn, "touchstart", (e) => {
    e.preventDefault();
    handleMouseDown(1);
  });
  bindListener(zoomIn, "touchend", () => handleMouseUp(1));

  bindListener(zoomOut, "mousedown", () => handleMouseDown(-1));
  bindListener(zoomOut, "mouseup", () => handleMouseUp(-1));
  bindListener(zoomOut, "mouseleave", stopZoom);
  bindListener(zoomOut, "touchstart", (e) => {
    e.preventDefault();
    handleMouseDown(-1);
  });
  bindListener(zoomOut, "touchend", () => handleMouseUp(-1));

  bindListener(zoomValue, "click", () => {
    const startZoomVal = zoomLevel;
    const targetZoom = 1.0;
    const startDistance = CONFIG.defaultCameraZ / startZoomVal;
    const targetDistance = CONFIG.defaultCameraZ / targetZoom;

    animateValue(
      0,
      1,
      600,
      (progress) => {
        const ease = 1 - Math.pow(1 - progress, 3);
        zoomLevel = startZoomVal + (targetZoom - startZoomVal) * ease;
        camera.position.z = CONFIG.defaultCameraZ / zoomLevel;
        const distance =
          startDistance + (targetDistance - startDistance) * ease;
        updateZoomDisplay(zoomLevel, distance.toFixed(0));
      },
      () => {
        zoomLevel = 1.0;
        showStatusMessage("缩放已重置到100%", "info");
      },
    );
  });
}

function setupWheelZoom(camera, renderer) {
  bindListener(
    renderer?.domElement,
    "wheel",
    (e) => {
      e.preventDefault();
      if (e.deltaY < 0) {
        zoomLevel = Math.min(zoomLevel + 0.1, CONFIG.maxZoom);
      } else {
        zoomLevel = Math.max(zoomLevel - 0.1, CONFIG.minZoom);
      }
      applyZoom(camera);
    },
    { passive: false },
  );
}

function applyZoom(camera) {
  camera.position.z = CONFIG.defaultCameraZ / zoomLevel;
  const distance = camera.position.z.toFixed(0);
  updateZoomDisplay(zoomLevel, distance);
}

function animateValue(start, end, duration, onUpdate, onComplete) {
  const startTime = performance.now();

  function update(currentTime) {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const easeProgress = 1 - Math.pow(1 - progress, 3);

    const current = start + (end - start) * easeProgress;
    onUpdate(current);

    if (progress < 1) {
      requestAnimationFrame(update);
    } else if (onComplete) {
      onComplete();
    }
  }

  requestAnimationFrame(update);
}

export function resetView(camera) {
  if (!earthObj) return;

  function animateToView(targetLat, targetLon, targetRotLon) {
    const latRot = (targetLat * Math.PI) / 180;
    const targetRotX =
      EARTH_CONFIG.tiltRad + latRot * EARTH_CONFIG.latCoefficient;
    const targetRotY = -((targetRotLon * Math.PI) / 180);

    const startRotX = earthObj.rotation.x;
    const startRotY = earthObj.rotation.y;
    const startZoom = zoomLevel;
    const targetZoom = 1.0;

    animateValue(
      0,
      1,
      800,
      (progress) => {
        const ease = 1 - Math.pow(1 - progress, 3);
        earthObj.rotation.x = startRotX + (targetRotX - startRotX) * ease;
        earthObj.rotation.y = startRotY + (targetRotY - startRotY) * ease;

        zoomLevel = startZoom + (targetZoom - startZoom) * ease;
        camera.position.z = CONFIG.defaultCameraZ / zoomLevel;
        updateZoomDisplay(zoomLevel, camera.position.z.toFixed(0));
      },
      () => {
        zoomLevel = 1.0;
        showStatusMessage("视角已重置", "info");
      },
    );
  }

  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (pos) =>
        animateToView(
          pos.coords.latitude,
          pos.coords.longitude,
          -pos.coords.longitude,
        ),
      () =>
        animateToView(
          EARTH_CONFIG.chinaLat,
          EARTH_CONFIG.chinaLon,
          EARTH_CONFIG.chinaRotLon,
        ),
      { timeout: 5000, enableHighAccuracy: false },
    );
  } else {
    animateToView(
      EARTH_CONFIG.chinaLat,
      EARTH_CONFIG.chinaLon,
      EARTH_CONFIG.chinaRotLon,
    );
  }

  clearLockedObject();
}

function setupRotateControls(camera) {
  const rotateBtn = document.getElementById("rotate-toggle");
  const resetViewBtn = document.getElementById("reset-view");

  bindListener(rotateBtn, "click", () => {
    const isRotating = toggleAutoRotate();
    showStatusMessage(isRotating ? "自动旋转已开启" : "自动旋转已暂停", "info");
  });

  updateRotateUI();

  bindListener(resetViewBtn, "click", () => {
    resetView(camera);
  });
}

function setupTerrainControls() {
  const container = document.getElementById("container");
  const searchBtn = document.getElementById("search-action");
  const infoGroup = document.getElementById("info-control-group");
  const infoTrigger = document.getElementById("info-trigger");
  const terrainBtn = document.getElementById("toggle-terrain");
  const satellitesBtn = document.getElementById("toggle-satellites");
  const trailsBtn = document.getElementById("toggle-trails");
  const cablesBtn = document.getElementById("toggle-cables");
  const layoutBtn = document.getElementById("layout-toggle");
  const reloadBtn = document.getElementById("reload-data");
  const zoomGroup = document.getElementById("zoom-control-group");
  const zoomTrigger = document.getElementById("zoom-trigger");

  if (trailsBtn) {
    trailsBtn.classList.add("active");
    const tooltip = trailsBtn.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = "隐藏轨迹";
  }

  bindListener(searchBtn, "click", () => {
    showStatusMessage("搜索功能待开发", "info");
  });

  bindListener(terrainBtn, "click", function () {
    showTerrain = !showTerrain;
    toggleTerrain(showTerrain);
    this.classList.toggle("active", showTerrain);
    const tooltip = this.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = showTerrain ? "隐藏地形" : "显示地形";
    const terrainStatus = document.getElementById("terrain-status");
    if (terrainStatus)
      terrainStatus.textContent = showTerrain ? "开启" : "关闭";
    showStatusMessage(showTerrain ? "地形已显示" : "地形已隐藏", "info");
  });

  bindListener(satellitesBtn, "click", function () {
    const showSats = !getShowSatellites();
    if (!showSats) {
      clearLockedObject();
    }
    toggleSatellites(showSats);
    this.classList.toggle("active", showSats);
    const tooltip = this.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = showSats ? "隐藏卫星" : "显示卫星";
    const satelliteCountEl = document.getElementById("satellite-count");
    if (satelliteCountEl)
      satelliteCountEl.textContent = getSatelliteCount() + " 颗";
    showStatusMessage(showSats ? "卫星已显示" : "卫星已隐藏", "info");
  });

  bindListener(trailsBtn, "click", function () {
    const isActive = this.classList.contains("active");
    const nextShowTrails = !isActive;
    toggleTrails(nextShowTrails);
    this.classList.toggle("active", nextShowTrails);
    const tooltip = this.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = nextShowTrails ? "隐藏轨迹" : "显示轨迹";
    showStatusMessage(nextShowTrails ? "轨迹已显示" : "轨迹已隐藏", "info");
  });

  bindListener(cablesBtn, "click", function () {
    const showNextCables = !getShowCables();
    if (!showNextCables) {
      clearLockedObject();
    }
    toggleCables(showNextCables);
    this.classList.toggle("active", showNextCables);
    const tooltip = this.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = showNextCables ? "隐藏线缆" : "显示线缆";
    showStatusMessage(showNextCables ? "线缆已显示" : "线缆已隐藏", "info");
  });

  bindListener(reloadBtn, "click", async () => {
    await reloadData();
  });

  bindListener(zoomTrigger, "click", (event) => {
    event.stopPropagation();
    infoGroup?.classList.remove("open");
    zoomGroup?.classList.toggle("open");
  });

  bindListener(zoomGroup, "click", (event) => {
    event.stopPropagation();
  });

  bindListener(infoTrigger, "click", (event) => {
    event.stopPropagation();
    zoomGroup?.classList.remove("open");
    infoGroup?.classList.toggle("open");
  });

  bindListener(infoGroup, "click", (event) => {
    event.stopPropagation();
  });

  bindListener(document, "click", (event) => {
    if (zoomGroup?.classList.contains("open")) {
      if (!zoomGroup.contains(event.target)) {
        zoomGroup.classList.remove("open");
      }
    }
    if (infoGroup?.classList.contains("open")) {
      if (!infoGroup.contains(event.target)) {
        infoGroup.classList.remove("open");
      }
    }
  });

  bindListener(layoutBtn, "click", () => {
    const expanded = toggleLayoutExpanded(container);
    showStatusMessage(expanded ? "布局已最大化" : "布局已恢复", "info");
  });

  updateLayoutUI(container);
}

function setupLiquidGlassInteractions() {
  const surfaces = document.querySelectorAll(".liquid-glass-surface");

  const resetSurface = (surface) => {
    surface.style.setProperty("--elastic-x", "0px");
    surface.style.setProperty("--elastic-y", "0px");
    surface.style.setProperty("--tilt-x", "0deg");
    surface.style.setProperty("--tilt-y", "0deg");
    surface.style.setProperty("--glow-x", "50%");
    surface.style.setProperty("--glow-y", "22%");
    surface.style.setProperty("--glow-opacity", "0.24");
    surface.classList.remove("is-pressed");
  };

  surfaces.forEach((surface) => {
    resetSurface(surface);

    bindListener(surface, "pointermove", (event) => {
      const rect = surface.getBoundingClientRect();
      const px = (event.clientX - rect.left) / rect.width;
      const py = (event.clientY - rect.top) / rect.height;
      const offsetX = (px - 0.5) * 6;
      const offsetY = (py - 0.5) * 6;
      const tiltX = (0.5 - py) * 8;
      const tiltY = (px - 0.5) * 10;

      surface.style.setProperty("--elastic-x", `${offsetX.toFixed(2)}px`);
      surface.style.setProperty("--elastic-y", `${offsetY.toFixed(2)}px`);
      surface.style.setProperty("--tilt-x", `${tiltX.toFixed(2)}deg`);
      surface.style.setProperty("--tilt-y", `${tiltY.toFixed(2)}deg`);
      surface.style.setProperty("--glow-x", `${(px * 100).toFixed(1)}%`);
      surface.style.setProperty("--glow-y", `${(py * 100).toFixed(1)}%`);
      surface.style.setProperty("--glow-opacity", "0.34");
    });

    bindListener(surface, "pointerenter", () => {
      surface.style.setProperty("--glow-opacity", "0.28");
    });

    bindListener(surface, "pointerleave", () => {
      resetSurface(surface);
    });

    bindListener(surface, "pointerdown", () => {
      surface.classList.add("is-pressed");
    });

    bindListener(surface, "pointerup", () => {
      surface.classList.remove("is-pressed");
    });

    bindListener(surface, "pointercancel", () => {
      resetSurface(surface);
    });
  });
}

export function teardownControls() {
  resetCleanup();
}

export function getAutoRotate() {
  return autoRotate;
}

function updateRotateUI() {
  const btn = document.getElementById("rotate-toggle");
  if (btn) {
    btn.classList.toggle("active", autoRotate);
    btn.classList.toggle("is-stopped", !autoRotate);
    const tooltip = btn.querySelector(".tooltip");
    if (tooltip) tooltip.textContent = autoRotate ? "暂停旋转" : "开始旋转";
  }
}

export function setAutoRotate(value) {
  autoRotate = value;
  updateRotateUI();
}

export function toggleAutoRotate() {
  autoRotate = !autoRotate;
  updateRotateUI();
  clearLockedObject();
  return autoRotate;
}

export function getZoomLevel() {
  return zoomLevel;
}

export function getShowTerrain() {
  return showTerrain;
}

function updateLayoutUI(container) {
  if (container) {
    container.classList.toggle("layout-expanded", layoutExpanded);
  }

  const btn = document.getElementById("layout-toggle");
  if (btn) {
    btn.classList.toggle("active", layoutExpanded);
    const tooltip = btn.querySelector(".tooltip");
    const nextLabel = layoutExpanded ? "恢复布局" : "最大化布局";
    btn.title = nextLabel;
    if (tooltip) tooltip.textContent = nextLabel;
  }
}

function toggleLayoutExpanded(container) {
  layoutExpanded = !layoutExpanded;
  updateLayoutUI(container);
  return layoutExpanded;
}
