<script setup lang="ts">
import { storeToRefs } from "pinia";
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { GameViewer } from "./GameViewer";
import CollapsibleHudPanel from "./components/CollapsibleHudPanel.vue";
import HtmlInfoPanel from "./components/HtmlInfoPanel.vue";
import ViewerHistoryLayer from "./components/ViewerHistoryLayer.vue";
import ViewerEntityBrowserPanel from "./components/ViewerEntityBrowserPanel.vue";
import ViewerEntityInspectorPanel from "./components/ViewerEntityInspectorPanel.vue";
import ViewerShipOrderContextMenu from "./components/ViewerShipOrderContextMenu.vue";
import GmOpsWindow from "./components/gm/GmOpsWindow.vue";
import GmTelemetryWindow from "./components/gm/GmTelemetryWindow.vue";
import GmSettingsWindow from "./components/gm/GmSettingsWindow.vue";
import AuthSessionPanel from "./components/AuthSessionPanel.vue";
import AuthLandingPage from "./components/AuthLandingPage.vue";
import { useShipAutomationCatalogStore } from "./ui/stores/shipAutomationCatalogStore";
import { createViewerHudState } from "./viewerHudState";
import { useAuthStore } from "./ui/stores/authStore";
import { useViewerSelectionStore } from "./ui/stores/viewerSelection";
import type { Selectable } from "./viewerTypes";

const canvasHostEl = ref<HTMLDivElement | null>(null);
const historyLayerHostEl = ref<HTMLDivElement | null>(null);
const marqueeEl = ref<HTMLDivElement | null>(null);
const hoverLabelEl = ref<HTMLDivElement | null>(null);
const hoverConnectorLineEl = ref<SVGLineElement | null>(null);

const hudState = createViewerHudState();
const authStore = useAuthStore();
const automationCatalogStore = useShipAutomationCatalogStore();
const selectionStore = useViewerSelectionStore();
const { selectedEntityId, selectedEntityLabel } = storeToRefs(selectionStore);
const { canAccessGm } = storeToRefs(authStore);
let viewer: GameViewer | undefined;

const gmOpsOpen = ref(false);
const gmTelemetryOpen = ref(false);
const gmSettingsOpen = ref(false);
const gmMenuOpen = ref(false);

onMounted(async () => {
  void automationCatalogStore.load();
  await startViewerIfAuthenticated();
});

onBeforeUnmount(() => {
  viewer?.dispose();
});

watch(() => authStore.isAuthenticated, async (isAuthenticated) => {
  if (isAuthenticated) {
    await startViewerIfAuthenticated();
    return;
  }

  viewer?.dispose();
  viewer = undefined;
});

function onHistoryWindowResize(id: string, width: number, height: number) {
  const windowState = hudState.historyWindows.find((entry) => entry.id === id);
  if (!windowState) {
    return;
  }

  windowState.width = width;
  windowState.height = height;
}

function onOpenHistory(selection: Selectable) {
  viewer?.openHistoryWindow(selection);
}

function onFocusSelection(selection: Selectable, cameraMode?: "follow" | "tactical") {
  viewer?.focusSelection(selection, cameraMode);
}

async function startViewerIfAuthenticated() {
  if (!authStore.isAuthenticated || viewer) {
    return;
  }

  await nextTick();
  if (
    !canvasHostEl.value
    || !historyLayerHostEl.value
    || !marqueeEl.value
    || !hoverLabelEl.value
    || !hoverConnectorLineEl.value
  ) {
    throw new Error("Viewer HUD mount failed");
  }

  viewer = new GameViewer(canvasHostEl.value, {
    state: hudState,
    selectionStore,
    historyLayerEl: historyLayerHostEl.value,
    marqueeEl: marqueeEl.value,
    hoverLabelEl: hoverLabelEl.value,
    hoverConnectorLineEl: hoverConnectorLineEl.value,
  });
  void viewer.start();
}
</script>

<template>
  <AuthLandingPage v-if="!authStore.isAuthenticated" />
  <div v-else class="viewer-app">
    <div
      ref="canvasHostEl"
      class="viewer-canvas-host"
    />
    <div class="pointer-events-none fixed inset-0">
      <div class="absolute left-5 top-5 flex max-h-[calc(100vh-40px)] w-[min(360px,calc(100vw-40px))] flex-col gap-4 overflow-hidden max-[760px]:right-5 max-[760px]:bottom-[148px] max-[760px]:w-auto max-[760px]:max-h-[38vh]">
        <AuthSessionPanel />
        <CollapsibleHudPanel
          v-model:collapsed="hudState.gamePanel.collapsed"
          class-name="topbar"
          panel-name="game"
          title="Game"
          :summary="hudState.gamePanel.summary"
          :body-text="hudState.gamePanel.bodyText"
        />
        <CollapsibleHudPanel
          v-model:collapsed="hudState.networkPanel.collapsed"
          class-name="network-panel"
          panel-name="network"
          title="Network"
          :summary="hudState.networkPanel.summary"
          :body-text="hudState.networkPanel.bodyText"
        />
        <CollapsibleHudPanel
          v-model:collapsed="hudState.performancePanel.collapsed"
          class-name="performance-panel"
          panel-name="performance"
          title="Performance"
          :summary="hudState.performancePanel.summary"
          :body-text="hudState.performancePanel.bodyText"
        />
        <ViewerEntityBrowserPanel
          class="min-h-0 flex-1"
          @focus="(selection, cameraMode) => onFocusSelection(selection, cameraMode)"
        />
      </div>

      <div class="absolute right-5 top-5 flex max-h-[calc(100vh-40px)] w-[min(380px,calc(100vw-40px))] flex-col gap-4 overflow-hidden max-[760px]:bottom-[148px] max-[760px]:left-5 max-[760px]:right-5 max-[760px]:top-auto max-[760px]:max-h-[38vh] max-[760px]:w-auto">
        <HtmlInfoPanel
          class-name="system-panel-section"
          title="System"
          :subtitle="hudState.systemPanel.title"
          :body-html="hudState.systemPanel.bodyHtml"
          :hidden="hudState.systemPanel.hidden"
          subtitle-class="system-title"
          body-class="system-body"
        />
        <ViewerEntityInspectorPanel
          class="min-h-0 flex-1"
          :fallback-title="hudState.detailPanel.title"
          :fallback-html="hudState.detailPanel.bodyHtml"
          @focus="(selection, cameraMode) => onFocusSelection(selection, cameraMode)"
        />
        <div
          class="pointer-events-auto rounded-xl bg-[rgba(255,116,88,0.14)] px-3.5 py-3 text-[#ffd8cf]"
          :hidden="hudState.error.hidden"
        >
          {{ hudState.error.message }}
        </div>
        <button
          v-if="selectedEntityId"
          type="button"
          class="selection-action-button pointer-events-auto self-end rounded-full border border-white/10 bg-white/5 px-3.5 py-2.5 text-sm text-[color:var(--viewer-text)] transition hover:bg-white/10"
          @click="selectionStore.clearSelection('ui')"
        >
          Clear {{ selectedEntityLabel ?? "Selection" }}
        </button>
      </div>

      <div ref="historyLayerHostEl">
        <ViewerHistoryLayer
          :windows="hudState.historyWindows"
          @resize="onHistoryWindowResize"
        />
      </div>

      <div v-if="canAccessGm" class="gm-launcher" @mouseleave="gmMenuOpen = false">
        <div v-if="gmMenuOpen" class="gm-launcher-menu">
          <button
            type="button"
            class="gm-launcher-item"
            :class="gmOpsOpen ? 'gm-launcher-item--active' : ''"
            @click="gmOpsOpen = !gmOpsOpen; gmMenuOpen = false"
          >
          Entities
          </button>
          <button
            type="button"
            class="gm-launcher-item"
            :class="gmTelemetryOpen ? 'gm-launcher-item--active' : ''"
            @click="gmTelemetryOpen = !gmTelemetryOpen; gmMenuOpen = false"
          >
            Telemetry
          </button>
          <button
            type="button"
            class="gm-launcher-item"
            :class="gmSettingsOpen ? 'gm-launcher-item--active' : ''"
            @click="gmSettingsOpen = !gmSettingsOpen; gmMenuOpen = false"
          >
            Settings
          </button>
        </div>
        <button
          type="button"
          class="gm-launcher-trigger"
          :class="gmMenuOpen ? 'gm-launcher-trigger--open' : ''"
          @click="gmMenuOpen = !gmMenuOpen"
        >
          GM
        </button>
      </div>

      <GmOpsWindow
        v-if="gmOpsOpen"
        @close="gmOpsOpen = false"
        @focus="(id, kind) => onFocusSelection({ kind, id }, kind === 'ship' ? 'follow' : 'tactical')"
      />
      <GmTelemetryWindow
        v-if="gmTelemetryOpen"
        @close="gmTelemetryOpen = false"
      />
      <GmSettingsWindow
        v-if="gmSettingsOpen"
        @close="gmSettingsOpen = false"
      />

      <div
        ref="marqueeEl"
        class="marquee-box"
        :style="{
          display: hudState.marquee.visible ? 'block' : 'none',
          left: `${hudState.marquee.x}px`,
          top: `${hudState.marquee.y}px`,
          width: `${hudState.marquee.width}px`,
          height: `${hudState.marquee.height}px`,
        }"
      />

      <svg
        class="hover-connector-svg"
        aria-hidden="true"
      >
        <line
          ref="hoverConnectorLineEl"
          class="hover-connector-line"
          :x1="hudState.hoverLabel.x1"
          :y1="hudState.hoverLabel.y1"
          :x2="hudState.hoverLabel.x2"
          :y2="hudState.hoverLabel.y2"
          :hidden="hudState.hoverLabel.connectorHidden"
        />
      </svg>

      <div
        ref="hoverLabelEl"
        class="hover-label"
        :hidden="hudState.hoverLabel.hidden"
        :style="{
          left: `${hudState.hoverLabel.x}px`,
          top: `${hudState.hoverLabel.y}px`,
        }"
      >
        {{ hudState.hoverLabel.text }}
      </div>

      <ViewerShipOrderContextMenu />
    </div>
  </div>
</template>
