<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { storeToRefs } from "pinia";
import { enqueueShipOrder } from "../api";
import { getShipOrderLabel, getShipOrderNotes, getShipOrderSupportStatusLabel } from "../shipAutomationPresentation";
import { useAuthStore } from "../ui/stores/authStore";
import { useGmStore } from "../ui/stores/gmStore";
import { usePlayerFactionStore } from "../ui/stores/playerFactionStore";
import { useShipAutomationCatalogStore } from "../ui/stores/shipAutomationCatalogStore";
import { useViewerOrderContextMenuStore } from "../ui/stores/viewerOrderContextMenu";
import { useViewerSelectionStore } from "../ui/stores/viewerSelection";

type MenuAction =
  | "mine-resource"
  | "fly-to-and-wait"
  | "follow"
  | "attack";

interface OrderMenuActionEntry {
  key: MenuAction;
  orderKind: string;
  label: string;
  detail?: string;
  supportStatus?: string | null;
  notes?: string | null;
}

const rootEl = ref<HTMLElement | null>(null);
const authStore = useAuthStore();
const gmStore = useGmStore();
const playerStore = usePlayerFactionStore();
const automationStore = useShipAutomationCatalogStore();
const selectionStore = useViewerSelectionStore();
const orderMenuStore = useViewerOrderContextMenuStore();

const { playerFaction } = storeToRefs(playerStore);
const { selectedEntityId, selectedEntityKind } = storeToRefs(selectionStore);
const { isOpen, x, y, target } = storeToRefs(orderMenuStore);

const selectedShip = computed(() => {
  if (selectedEntityKind.value !== "ship" || !selectedEntityId.value) {
    return null;
  }

  return gmStore.ships.find((ship) => ship.id === selectedEntityId.value) ?? null;
});

const canControlSelectedShip = computed(() => {
  if (!selectedShip.value) {
    return false;
  }

  if (authStore.canAccessGm && !authStore.isActingAsAlternateIdentity) {
    return true;
  }

  if (!playerFaction.value) {
    return false;
  }

  return playerFaction.value.assetRegistry.shipIds.includes(selectedShip.value.id);
});

function emptyActions(): OrderMenuActionEntry[] {
  return [];
}

const actions = computed<OrderMenuActionEntry[]>(() => {
  if (!target.value || !selectedShip.value || !canControlSelectedShip.value) {
    return emptyActions();
  }

  switch (target.value.selection.kind) {
    case "node":
      return [{
        key: "mine-resource",
        orderKind: "mine-and-deliver",
        label: getShipOrderLabel("mine-and-deliver"),
        detail: `${target.value.itemId ?? "resource"} · ${target.value.systemId ?? selectedShip.value.systemId}`,
        supportStatus: getShipOrderSupportStatusLabel("mine-and-deliver"),
        notes: getShipOrderNotes("mine-and-deliver"),
      }];
    case "ship":
      if (target.value.selection.id === selectedShip.value.id) {
        return emptyActions();
      }
      return [
        {
          key: "follow",
          orderKind: "follow-ship",
          label: getShipOrderLabel("follow-ship"),
          detail: target.value.label,
          supportStatus: getShipOrderSupportStatusLabel("follow-ship"),
          notes: getShipOrderNotes("follow-ship"),
        },
        {
          key: "attack",
          orderKind: "attack-target",
          label: getShipOrderLabel("attack-target"),
          detail: target.value.label,
          supportStatus: getShipOrderSupportStatusLabel("attack-target"),
          notes: getShipOrderNotes("attack-target"),
        },
      ];
    case "station":
    case "celestial":
    case "construction-site":
      return [{
        key: "fly-to-and-wait",
        orderKind: "fly-and-wait",
        label: getShipOrderLabel("fly-and-wait"),
        detail: target.value.label,
        supportStatus: getShipOrderSupportStatusLabel("fly-and-wait"),
        notes: getShipOrderNotes("fly-and-wait"),
      }];
    case "system":
      return emptyActions();
    default:
      return emptyActions();
  }
});

const menuStyle = computed(() => ({
  left: `${Math.min(x.value, window.innerWidth - 280)}px`,
  top: `${Math.min(y.value, window.innerHeight - 240)}px`,
}));

watch([selectedEntityKind, selectedEntityId], () => {
  if (isOpen.value && selectedEntityKind.value !== "ship") {
    orderMenuStore.close();
  }
});

function closeMenu() {
  orderMenuStore.close();
}

async function runAction(action: MenuAction) {
  if (!selectedShip.value || !target.value || !canControlSelectedShip.value) {
    return;
  }

  if (action === "mine-resource") {
    const itemId = target.value.itemId;
    if (!itemId) {
      return;
    }

    const ship = await enqueueShipOrder(selectedShip.value.id, {
      kind: "mine-and-deliver",
      priority: 100,
      interruptCurrentPlan: true,
      label: `Mine ${itemId} in ${target.value.systemId ?? selectedShip.value.systemId}`,
      targetEntityId: null,
      targetSystemId: target.value.systemId ?? selectedShip.value.systemId,
      targetPosition: null,
      sourceStationId: null,
      destinationStationId: null,
      itemId,
      nodeId: target.value.selection.kind === "node" ? target.value.selection.id : null,
      constructionSiteId: null,
      moduleId: null,
      waitSeconds: 0,
      radius: 0,
      maxSystemRange: 0,
      knownStationsOnly: false,
    });
    gmStore.upsertShip(ship);
    closeMenu();
    return;
  }

  if (action === "fly-to-and-wait") {
    const ship = await enqueueShipOrder(selectedShip.value.id, {
      kind: "fly-and-wait",
      priority: 100,
      interruptCurrentPlan: true,
      label: `Fly to ${target.value.label}`,
      targetEntityId: null,
      targetSystemId: target.value.systemId ?? selectedShip.value.systemId,
      targetPosition: target.value.targetPosition ?? null,
      sourceStationId: null,
      destinationStationId: null,
      itemId: null,
      nodeId: null,
      constructionSiteId: null,
      moduleId: null,
      waitSeconds: 8,
      radius: 0,
      maxSystemRange: 0,
      knownStationsOnly: false,
    });
    gmStore.upsertShip(ship);
    closeMenu();
    return;
  }

  if (action === "follow") {
    const ship = await enqueueShipOrder(selectedShip.value.id, {
      kind: "follow-ship",
      priority: 100,
      interruptCurrentPlan: true,
      label: `Follow ${target.value.label}`,
      targetEntityId: target.value.selection.kind === "ship" ? target.value.selection.id : null,
      targetSystemId: target.value.systemId ?? null,
      targetPosition: null,
      sourceStationId: null,
      destinationStationId: null,
      itemId: null,
      nodeId: null,
      constructionSiteId: null,
      moduleId: null,
      waitSeconds: 6,
      radius: 22,
      maxSystemRange: 0,
      knownStationsOnly: false,
    });
    gmStore.upsertShip(ship);
    closeMenu();
    return;
  }

  if (action === "attack") {
    const ship = await enqueueShipOrder(selectedShip.value.id, {
      kind: "attack-target",
      priority: 100,
      interruptCurrentPlan: true,
      label: `Attack ${target.value.label}`,
      targetEntityId: target.value.selection.kind === "ship" ? target.value.selection.id : null,
      targetSystemId: target.value.systemId ?? null,
      targetPosition: null,
      sourceStationId: null,
      destinationStationId: null,
      itemId: null,
      nodeId: null,
      constructionSiteId: null,
      moduleId: null,
      waitSeconds: 0,
      radius: 0,
      maxSystemRange: 0,
      knownStationsOnly: false,
    });
    gmStore.upsertShip(ship);
    closeMenu();
  }
}

function onActionClick(action: { key: MenuAction }) {
  void runAction(action.key);
}

function onWindowPointerDown(event: PointerEvent) {
  if (!isOpen.value) {
    return;
  }

  if (rootEl.value?.contains(event.target as Node)) {
    return;
  }

  closeMenu();
}

function onWindowKeyDown(event: KeyboardEvent) {
  if (event.key === "Escape") {
    closeMenu();
  }
}

onMounted(() => {
  void automationStore.load();
  window.addEventListener("pointerdown", onWindowPointerDown, true);
  window.addEventListener("keydown", onWindowKeyDown);
});

onBeforeUnmount(() => {
  window.removeEventListener("pointerdown", onWindowPointerDown, true);
  window.removeEventListener("keydown", onWindowKeyDown);
});
</script>

<template>
  <section
    v-if="isOpen && target"
    ref="rootEl"
    class="viewer-order-context-menu pointer-events-auto"
    :style="menuStyle"
    @pointerdown.stop
    @contextmenu.prevent.stop
  >
    <header class="viewer-order-context-menu__header">
      <div class="viewer-order-context-menu__kicker">Direct Order</div>
      <h4>{{ target.label }}</h4>
      <p v-if="selectedShip">Selected ship: {{ selectedShip.name }}</p>
    </header>

    <div v-if="!selectedShip" class="viewer-order-context-menu__empty">
      Select a ship first.
    </div>
    <div v-else-if="!canControlSelectedShip" class="viewer-order-context-menu__empty">
      Direct orders are only available for player-owned ships or GM users.
    </div>
    <div v-else-if="actions.length === 0" class="viewer-order-context-menu__empty">
      No direct actions for this target yet.
    </div>
    <div v-else class="viewer-order-context-menu__actions">
      <button
        v-for="action in actions"
        :key="action.key"
        type="button"
        class="viewer-order-context-menu__action"
        @click="onActionClick(action)"
      >
        <span>{{ action.label }}</span>
        <strong v-if="action.detail">{{ action.detail }}</strong>
        <small v-if="action.supportStatus || action.notes">{{ [action.supportStatus, action.notes].filter(Boolean).join(" · ") }}</small>
      </button>
    </div>
  </section>
</template>
