import * as THREE from "three";
import { ViewerInteractionController } from "./viewerInteractionController";
import { ViewerNavigationController } from "./viewerNavigationController";
import { ViewerPresentationController } from "./viewerPresentationController";
import { ViewerSceneDataController } from "./viewerSceneDataController";
import { ViewerWorldLifecycle } from "./viewerWorldLifecycle";
import { ViewerHistoryWindowController } from "./viewerHistoryWindowController";
import { applyPanFromScreenDelta } from "./viewerCamera";
import { MAX_CAMERA_DISTANCE, MIN_CAMERA_DISTANCE } from "./viewerConstants";
import { useViewerSceneStore } from "./ui/stores/viewerScene";
import { useViewerOrderContextMenuStore } from "./ui/stores/viewerOrderContextMenu";
import { viewerPinia } from "./ui/stores/pinia";

export function createViewerControllers(host: any) {
  const sceneStore = useViewerSceneStore(viewerPinia);
  const orderContextMenuStore = useViewerOrderContextMenuStore(viewerPinia);
  const sceneDataController = new ViewerSceneDataController({
    documentRef: document,
    getWorldOrbitalTimeSeconds: () => host.world?.orbitalTimeSeconds,
    getOrbitalSimulationSpeed: () => host.world?.orbitalSimulation.simulatedSecondsPerRealSecond ?? 0,
    getWorldSeed: () => host.world?.seed ?? 1,
    getWorldTimeSyncMs: () => host.worldTimeSyncMs,
    getWorldPresentationContext: () => host.createWorldPresentationContext(),
    getActiveSystemId: () => host.activeSystemId,
    galaxySystemGroup: host.galaxyLayer.systemGroup,
    systemScene: host.systemLayer.scene,
    celestialGroup: host.systemLayer.celestialGroup,
    nodeGroup: host.systemLayer.nodeGroup,
    stationGroup: host.systemLayer.stationGroup,
    claimGroup: host.systemLayer.claimGroup,
    constructionSiteGroup: host.systemLayer.constructionSiteGroup,
    shipGroup: host.systemLayer.shipGroup,
    galaxySelectableTargets: host.galaxyLayer.selectableTargets,
    systemSelectableTargets: host.systemLayer.selectableTargets,
    systemVisuals: host.galaxyLayer.systemVisuals,
    planetVisuals: host.systemLayer.planetVisuals,
    celestialVisuals: host.systemLayer.celestialVisuals,
    nodeVisuals: host.systemLayer.nodeVisuals,
    stationVisuals: host.systemLayer.stationVisuals,
    claimVisuals: host.systemLayer.claimVisuals,
    constructionSiteVisuals: host.systemLayer.constructionSiteVisuals,
    shipVisuals: host.systemLayer.shipVisuals,
  });

  const navigationController = new ViewerNavigationController({
    getWorld: () => host.world,
    getWorldTimeSyncMs: () => host.worldTimeSyncMs,
    getActiveSystemId: () => host.activeSystemId,
    setActiveSystemId: (value) => {
      host.activeSystemId = value;
      sceneStore.setViewContext(value ?? null, host.povLevel);
    },
    onActiveSystemChanged: (oldId, newId) => {
      sceneDataController.onActiveSystemChanged(oldId, newId);
    },
    getCameraMode: () => host.cameraMode,
    setCameraMode: (value) => {
      host.cameraMode = value;
    },
    getCameraTargetShipId: () => host.cameraTargetShipId,
    setCameraTargetShipId: (value) => {
      host.cameraTargetShipId = value;
    },
    getCurrentDistance: () => host.currentDistance,
    getPovLevel: () => host.povLevel,
    getSelectedItems: () => host.selectedItems,
    getOrbitYaw: () => host.orbitYaw,
    getFollowOrbitYaw: () => host.followOrbitYaw,
    getFollowOrbitPitch: () => host.followOrbitPitch,
    galaxyAnchor: host.galaxyAnchor,
    systemAnchor: host.systemAnchor,
    galaxyCamera: host.galaxyLayer.camera,
    systemCamera: host.systemLayer.camera,
    shipVisuals: host.systemLayer.shipVisuals,
    nodeVisuals: host.systemLayer.nodeVisuals,
    planetVisuals: host.systemLayer.planetVisuals,
    systemVisuals: host.galaxyLayer.systemVisuals,
    followCameraPosition: host.followCameraPosition,
    followCameraFocus: host.followCameraFocus,
    followCameraDirection: host.followCameraDirection,
    followCameraDesiredDirection: host.followCameraDesiredDirection,
    followCameraOffset: host.followCameraOffset,
    createWorldPresentationContext: () => host.createWorldPresentationContext(),
    updatePanels: () => host.updatePanels(),
    updateGamePanel: (mode: string) => host.updateGamePanel(mode),
  });

  const presentationController = new ViewerPresentationController({
    renderer: host.renderer,
    hudState: host.hudState,
    galaxyScene: host.galaxyLayer.scene,
    galaxyCamera: host.galaxyLayer.camera,
    systemCamera: host.systemLayer.camera,
    galaxyAnchor: host.galaxyAnchor,
    systemAnchor: host.systemAnchor,
    ambienceGroup: host.universeLayer.ambienceGroup,
    networkStats: host.networkStats,
    performanceStats: host.performanceStats,
    getWorld: () => host.world,
    getActiveSystemId: () => host.activeSystemId,
    getCameraMode: () => host.cameraMode,
    getCameraTargetShipId: () => host.cameraTargetShipId,
    getPovLevel: () => host.povLevel,
    getSelectedItems: () => host.selectedItems,
    getWorldTimeSyncMs: () => host.worldTimeSyncMs,
    getCurrentDistance: () => host.currentDistance,
    planetVisuals: host.systemLayer.planetVisuals,
    systemVisuals: host.galaxyLayer.systemVisuals,
    createWorldPresentationContext: () => host.createWorldPresentationContext(),
  });

  const worldLifecycle = new ViewerWorldLifecycle({
    getWorld: () => host.world,
    setWorld: (world) => {
      host.world = world;
    },
    getWorldTimeSyncMs: () => host.worldTimeSyncMs,
    setWorldTimeSyncMs: (value) => {
      host.worldTimeSyncMs = value;
    },
    getWorldSignature: () => host.worldSignature,
    setWorldSignature: (value) => {
      host.worldSignature = value;
    },
    getStream: () => host.stream,
    setStream: (stream) => {
      host.stream = stream;
    },
    getCurrentStreamScopeKey: () => host.currentStreamScopeKey,
    setCurrentStreamScopeKey: (value) => {
      host.currentStreamScopeKey = value;
    },
    getPovLevel: () => host.povLevel,
    getActiveSystemId: () => host.activeSystemId,
    getSelectedItems: () => host.selectedItems,
    getCameraMode: () => host.cameraMode,
    getCameraTargetShipId: () => host.cameraTargetShipId,
    getNetworkStats: () => host.networkStats,
    getSystemSummaryVisuals: () => new Map(),
    hudState: host.hudState,
    worldLabel: () => host.world?.label ?? "",
    rebuildSystems: (systems) => sceneDataController.rebuildSystems(systems),
    syncCelestials: (celestials) => sceneDataController.syncCelestials(celestials),
    syncNodes: (nodes) => sceneDataController.syncNodes(nodes),
    syncStations: (stations) => sceneDataController.syncStations(stations),
    syncClaims: (claims) => sceneDataController.syncClaims(claims),
    syncConstructionSites: (sites) => sceneDataController.syncConstructionSites(sites),
    syncShips: (ships, tickIntervalMs) => sceneDataController.syncShips(ships, tickIntervalMs),
    applyCelestialDeltas: (celestials) => sceneDataController.applyCelestialDeltas(celestials),
    applyNodeDeltas: (nodes) => sceneDataController.applyNodeDeltas(nodes),
    applyStationDeltas: (stations) => sceneDataController.applyStationDeltas(stations),
    applyClaimDeltas: (claims) => sceneDataController.applyClaimDeltas(claims),
    applyConstructionSiteDeltas: (sites) => sceneDataController.applyConstructionSiteDeltas(sites),
    applyShipDeltas: (ships, tickIntervalMs) => sceneDataController.applyShipDeltas(ships, tickIntervalMs),
    refreshHistoryWindows: () => host.refreshHistoryWindows(),
    resolveFocusedCelestialId: () => host.resolveFocusedCelestialId(),
    updateSystemSummaries: () => host.updateSystemSummaries(),
    applyZoomPresentation: () => presentationController.applyZoomPresentation(),
    updateNetworkPanel: () => presentationController.updateNetworkPanel(),
    updateSystemPanel: () => host.updateSystemPanel(),
    updateGamePanel: (mode) => host.updateGamePanel(mode),
    describeSelectionParent: (selection) => host.describeSelectionParent(selection),
  });

  const historyController = new ViewerHistoryWindowController({
    historyWindows: host.historyWindows,
    getWorld: () => host.world,
    getHistoryWindowCounter: () => host.historyWindowCounter,
    setHistoryWindowCounter: (value) => {
      host.historyWindowCounter = value;
    },
    getHistoryWindowZCounter: () => host.historyWindowZCounter,
    setHistoryWindowZCounter: (value) => {
      host.historyWindowZCounter = value;
    },
    getHistoryWindowDragId: () => host.historyWindowDragId,
    setHistoryWindowDragId: (value) => {
      host.historyWindowDragId = value;
    },
    getHistoryWindowDragPointerId: () => host.historyWindowDragPointerId,
    setHistoryWindowDragPointerId: (value) => {
      host.historyWindowDragPointerId = value;
    },
    historyWindowDragOffset: host.historyWindowDragOffset,
    renderRecentEvents: (entityKind, entityId) => presentationController.renderRecentEvents(entityKind, entityId),
  });

  const interactionController = new ViewerInteractionController({
    renderer: host.renderer,
    raycaster: host.raycaster,
    mouse: host.mouse,
    galaxyCamera: host.galaxyLayer.camera,
    systemCamera: host.systemLayer.camera,
    galaxySelectableTargets: host.galaxyLayer.selectableTargets,
    systemSelectableTargets: host.systemLayer.selectableTargets,
    hoverLabelEl: host.hoverLabelEl,
    hoverConnectorLineEl: host.hoverConnectorLineEl,
    marqueeEl: host.marqueeEl,
    hudState: host.hudState,
    keyState: host.keyState,
    getWorld: () => host.world,
    getActiveSystemId: () => host.activeSystemId,
    getPovLevel: () => host.povLevel,
    getSelectedItems: () => host.selectedItems,
    setSelectedItems: (items) => {
      host.applySelectedItems(items, "viewer");
    },
    getDragMode: () => host.dragMode,
    setDragMode: (mode) => {
      host.dragMode = mode;
    },
    getDragPointerId: () => host.dragPointerId,
    setDragPointerId: (pointerId) => {
      host.dragPointerId = pointerId;
    },
    dragStart: host.dragStart,
    dragLast: host.dragLast,
    getMarqueeActive: () => host.marqueeActive,
    setMarqueeActive: (value) => {
      host.marqueeActive = value;
    },
    getSuppressClickSelection: () => host.suppressClickSelection,
    setSuppressClickSelection: (value) => {
      host.suppressClickSelection = value;
    },
    getDesiredDistance: () => host.desiredDistance,
    setDesiredDistance: (value) => {
      host.desiredDistance = value;
    },
    getCameraMode: () => host.cameraMode,
    setCameraMode: (value) => {
      host.cameraMode = value;
    },
    getCameraTargetShipId: () => host.cameraTargetShipId,
    setCameraTargetShipId: (value) => {
      host.cameraTargetShipId = value;
    },
    getFollowCameraPosition: () => host.followCameraPosition,
    getFollowCameraFocus: () => host.followCameraFocus,
    screenPointFromClient: (x, y) => presentationController.screenPointFromClient(x, y),
    applyPanDelta: (delta: THREE.Vector2) => {
      const bounds = host.renderer.domElement.getBoundingClientRect();
      applyPanFromScreenDelta(
        delta,
        host.orbitYaw,
        host.currentDistance,
        host.povLevel,
        host.activeSystemId,
        host.systemAnchor,
        host.galaxyAnchor,
        bounds.width,
        bounds.height,
        MIN_CAMERA_DISTANCE,
        MAX_CAMERA_DISTANCE,
      );
    },
    syncFollowStateFromSelection: () => navigationController.syncFollowStateFromSelection(),
    updatePanels: () => host.updatePanels(),
    focusOnSelection: (selection) => navigationController.focusOnSelection(selection),
    updateGamePanel: (mode) => host.updateGamePanel(mode),
    openOrderContextMenu: (x, y, target) => orderContextMenuStore.open(x, y, target),
    closeOrderContextMenu: () => orderContextMenuStore.close(),
    getStatsOverlayMode: () => host.hudState.statsOverlay.mode,
    setStatsOverlayMode: (mode) => {
      host.hudState.statsOverlay.mode = mode;
    },
    refreshStatsOverlay: () => presentationController.refreshStatsOverlay(),
    historyController,
  });

  return {
    historyController,
    sceneDataController,
    navigationController,
    presentationController,
    worldLifecycle,
    interactionController,
  };
}

export function wireViewerEvents(host: any) {
  const canvas = host.renderer.domElement;
  canvas.addEventListener("pointerdown", host.interactionController.onPointerDown);
  canvas.addEventListener("pointermove", host.interactionController.onPointerMove);
  canvas.addEventListener("pointerup", host.interactionController.onPointerUp);
  canvas.addEventListener("pointercancel", host.interactionController.onPointerUp);
  canvas.addEventListener("pointerleave", host.interactionController.onPointerUp);
  canvas.addEventListener("click", host.interactionController.onClick);
  canvas.addEventListener("contextmenu", host.interactionController.onContextMenu);
  canvas.addEventListener("dblclick", host.interactionController.onDoubleClick);
  canvas.addEventListener("wheel", host.interactionController.onWheel, { passive: false });
  host.historyLayerEl.addEventListener("click", host.interactionController.onHistoryLayerClick);
  host.historyLayerEl.addEventListener("pointerdown", host.interactionController.onHistoryLayerPointerDown);
  window.addEventListener("pointermove", host.interactionController.onHistoryWindowPointerMove);
  window.addEventListener("pointerup", host.interactionController.onHistoryWindowPointerUp);
  window.addEventListener("keydown", host.interactionController.onKeyDown);
  window.addEventListener("keyup", host.interactionController.onKeyUp);
  return () => {
    canvas.removeEventListener("pointerdown", host.interactionController.onPointerDown);
    canvas.removeEventListener("pointermove", host.interactionController.onPointerMove);
    canvas.removeEventListener("pointerup", host.interactionController.onPointerUp);
    canvas.removeEventListener("pointercancel", host.interactionController.onPointerUp);
    canvas.removeEventListener("pointerleave", host.interactionController.onPointerUp);
    canvas.removeEventListener("click", host.interactionController.onClick);
    canvas.removeEventListener("contextmenu", host.interactionController.onContextMenu);
    canvas.removeEventListener("dblclick", host.interactionController.onDoubleClick);
    canvas.removeEventListener("wheel", host.interactionController.onWheel);
    host.historyLayerEl.removeEventListener("click", host.interactionController.onHistoryLayerClick);
    host.historyLayerEl.removeEventListener("pointerdown", host.interactionController.onHistoryLayerPointerDown);
    window.removeEventListener("pointermove", host.interactionController.onHistoryWindowPointerMove);
    window.removeEventListener("pointerup", host.interactionController.onHistoryWindowPointerUp);
    window.removeEventListener("keydown", host.interactionController.onKeyDown);
    window.removeEventListener("keyup", host.interactionController.onKeyUp);
  };
}
