<script setup lang="ts">
import { storeToRefs } from "pinia";
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { GameViewer } from "./GameViewer";
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 PlayerOnboardingPanel from "./components/PlayerOnboardingPanel.vue";
import { fetchPlayerFaction } from "./api";
import { useShipAutomationCatalogStore } from "./ui/stores/shipAutomationCatalogStore";
import { createViewerHudState } from "./viewerHudState";
import { useAuthStore } from "./ui/stores/authStore";
import { usePlayerFactionStore } from "./ui/stores/playerFactionStore";
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 playerFactionStore = usePlayerFactionStore();
const automationCatalogStore = useShipAutomationCatalogStore();
const selectionStore = useViewerSelectionStore();
const { selectedEntityId, selectedEntityLabel } = storeToRefs(selectionStore);
const { canAccessGm, effectivePlayerId } = storeToRefs(authStore);
const { playerFaction } = storeToRefs(playerFactionStore);
let viewer: GameViewer | undefined;

const gmOpsOpen = ref(false);
const gmTelemetryOpen = ref(false);
const gmSettingsOpen = ref(false);
const gmMenuOpen = ref(false);
const leftSidebarTab = ref<"player" | "entities">("player");
const playerContextReady = ref(false);

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

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

watch(
  [() => authStore.isAuthenticated, () => effectivePlayerId.value],
  async ([isAuthenticated]) => {
    if (!isAuthenticated) {
      playerContextReady.value = false;
      playerFactionStore.setPlayerFaction(null);
      viewer?.dispose();
      viewer = undefined;
      return;
    }

    await refreshPlayerContext();
    await startViewerIfAuthenticated();
  },
  { immediate: true },
);

watch(
  () => playerFaction.value?.requiresOnboarding ?? false,
  async (requiresOnboarding) => {
    if (requiresOnboarding) {
      viewer?.dispose();
      viewer = undefined;
      return;
    }

    await startViewerIfAuthenticated();
  },
);

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 || !playerContextReady.value || playerFaction.value?.requiresOnboarding) {
    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();
}

async function refreshPlayerContext() {
  if (!authStore.isAuthenticated) {
    playerContextReady.value = false;
    playerFactionStore.setPlayerFaction(null);
    return;
  }

  playerContextReady.value = false;
  try {
    playerFactionStore.setPlayerFaction(await fetchPlayerFaction());
  } catch {
    playerFactionStore.setPlayerFaction(null);
  } finally {
    playerContextReady.value = true;
  }
}
</script>

<template>
  <AuthLandingPage v-if="!authStore.isAuthenticated" />
  <div v-else-if="!playerContextReady" class="auth-landing">
    <div class="auth-landing__backdrop" />
    <div class="auth-landing__hero">
      <h1>Preparing player context</h1>
      <p>Loading your in-universe identity and ownership state.</p>
    </div>
  </div>
  <PlayerOnboardingPanel v-else-if="playerContextReady && playerFaction?.requiresOnboarding" />
  <div v-else class="viewer-app">
    <div
      ref="canvasHostEl"
      class="viewer-canvas-host"
    />
    <div class="pointer-events-none fixed inset-0">
      <div class="viewer-left-sidebar-dock">
        <section class="viewer-left-sidebar pointer-events-auto">
          <div class="viewer-left-sidebar__tabs">
            <button
              type="button"
              class="viewer-left-sidebar__tab"
              :class="leftSidebarTab === 'player' ? 'viewer-left-sidebar__tab--active' : ''"
              @click="leftSidebarTab = 'player'"
            >
              Player Informations
            </button>
            <button
              type="button"
              class="viewer-left-sidebar__tab"
              :class="leftSidebarTab === 'entities' ? 'viewer-left-sidebar__tab--active' : ''"
              @click="leftSidebarTab = 'entities'"
            >
              Entities
            </button>
          </div>

          <div class="viewer-left-sidebar__body">
            <div
              v-if="leftSidebarTab === 'player'"
              class="viewer-left-sidebar__panel viewer-left-sidebar__panel--player"
            >
              <AuthSessionPanel />
            </div>
            <ViewerEntityBrowserPanel
              v-else
              class="viewer-left-sidebar__panel viewer-left-sidebar__panel--entities"
              @focus="(selection, cameraMode) => onFocusSelection(selection, cameraMode)"
            />
          </div>
        </section>
      </div>

      <div
        v-if="hudState.statsOverlay.lines.length > 0"
        class="viewer-stats-overlay-dock"
      >
        <div
          class="viewer-stats-overlay"
          :class="hudState.statsOverlay.mode === 'compact' ? 'viewer-stats-overlay--compact' : ''"
        >
          <div
            v-for="(line, index) in hudState.statsOverlay.lines"
            :key="`${index}-${line}`"
            class="viewer-stats-overlay__line"
            :class="line === '' ? 'viewer-stats-overlay__line--spacer' : ''"
          >
            {{ line === "" ? "\u00A0" : line }}
          </div>
        </div>
      </div>

      <div
        v-if="!hudState.systemPanel.hidden"
        class="viewer-system-label-dock"
      >
        <div class="viewer-system-label">
          <div class="viewer-system-label__title">
            {{ hudState.systemPanel.title }}
          </div>
          <div class="viewer-system-label__subtitle">
            {{ hudState.systemPanel.bodyHtml }}
          </div>
        </div>
      </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">
        <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 }, '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>
