<script setup lang="ts">
import { computed, ref } from "vue";
import { storeToRefs } from "pinia";
import { getShipBehaviorLabel } from "../shipAutomationPresentation";
import { useGmStore } from "../ui/stores/gmStore";
import { usePlayerFactionStore } from "../ui/stores/playerFactionStore";
import { useViewerSceneStore } from "../ui/stores/viewerScene";
import { useViewerSelectionStore, type ViewerSelectionSummary } from "../ui/stores/viewerSelection";
import type { Selectable } from "../viewerTypes";

type BrowserTab = "visible" | "owned";

interface BrowserItem {
  key: string;
  label: string;
  subtitle: string;
  meta?: string;
  selection?: ViewerSelectionSummary;
  focusSelection?: Selectable;
  focusMode?: "follow" | "tactical";
}

interface BrowserSection {
  key: string;
  label: string;
  count: number;
  items: BrowserItem[];
}

const emit = defineEmits<{
  focus: [selection: Selectable, cameraMode?: "follow" | "tactical"];
}>();

const gmStore = useGmStore();
const playerStore = usePlayerFactionStore();
const selectionStore = useViewerSelectionStore();
const sceneStore = useViewerSceneStore();

const { selectedEntityId, selectedEntityKind } = storeToRefs(selectionStore);
const { playerFaction } = storeToRefs(playerStore);
const { activeSystemId, povLevel } = storeToRefs(sceneStore);

const activeTab = ref<BrowserTab>("visible");
const searchText = ref("");

function normalize(text: string) {
  return text.trim().toLowerCase();
}

function matchesSearch(item: BrowserItem, search: string) {
  if (!search) {
    return true;
  }

  const haystack = `${item.label} ${item.subtitle} ${item.meta ?? ""}`.toLowerCase();
  return haystack.includes(search);
}

function titleCase(value: string | null | undefined) {
  if (!value) {
    return "Unknown";
  }

  return value
    .replace(/([a-z])([A-Z])/g, "$1 $2")
    .replace(/[-_]+/g, " ")
    .replace(/\s+/g, " ")
    .trim()
    .replace(/\b\w/g, (part) => part.toUpperCase());
}

function buildVisibleSections(): BrowserSection[] {
  const sections: BrowserSection[] = [];

  if (povLevel.value === "galaxy" || !activeSystemId.value) {
    const systems = [...gmStore.systems]
      .sort((left, right) => left.label.localeCompare(right.label))
      .map<BrowserItem>((system) => ({
        key: `system-${system.id}`,
        label: system.label,
        subtitle: `${system.planets.length} planets · ${system.stars.length} stars`,
        meta: system.id,
        selection: { id: system.id, kind: "system", label: system.label },
        focusSelection: { kind: "system", id: system.id },
        focusMode: "tactical",
      }));
    sections.push({
      key: "systems",
      label: "Systems",
      count: systems.length,
      items: systems,
    });
    return sections;
  }

  const systemId = activeSystemId.value;
  const ships = gmStore.ships
    .filter((ship) => ship.systemId === systemId)
    .sort((left, right) => left.name.localeCompare(right.name))
    .map<BrowserItem>((ship) => ({
      key: `ship-${ship.id}`,
      label: ship.name,
      subtitle: `${titleCase(ship.type)} · ${titleCase(ship.state)}`,
      meta: `${getShipBehaviorLabel(ship.defaultBehavior.kind)}${ship.defaultBehavior.itemId ? ` · ${ship.defaultBehavior.itemId}` : ""}`,
      selection: { id: ship.id, kind: "ship", label: ship.name },
      focusSelection: { kind: "ship", id: ship.id },
      focusMode: "follow",
    }));
  const stations = gmStore.stations
    .filter((station) => station.systemId === systemId)
    .sort((left, right) => left.label.localeCompare(right.label))
    .map<BrowserItem>((station) => ({
      key: `station-${station.id}`,
      label: station.label,
      subtitle: `${titleCase(station.category)} · Docked ${station.dockedShips}/${station.dockingPads}`,
      meta: station.factionId,
      selection: { id: station.id, kind: "station", label: station.label },
      focusSelection: { kind: "station", id: station.id },
      focusMode: "tactical",
    }));

  sections.push({
    key: "ships",
    label: "Ships",
    count: ships.length,
    items: ships,
  });
  sections.push({
    key: "stations",
    label: "Stations",
    count: stations.length,
    items: stations,
  });

  return sections;
}

function buildOwnedSections(): BrowserSection[] {
  const player = playerFaction.value;
  if (!player) {
    return [];
  }

  const ships = player.assetRegistry.shipIds
    .map((shipId) => gmStore.ships.find((ship) => ship.id === shipId))
    .filter((ship): ship is NonNullable<typeof ship> => ship != null)
    .sort((left, right) => left.name.localeCompare(right.name))
    .map<BrowserItem>((ship) => ({
      key: `owned-ship-${ship.id}`,
      label: ship.name,
      subtitle: `${ship.systemId} · ${titleCase(ship.state)}`,
      meta: getShipBehaviorLabel(ship.defaultBehavior.kind),
      selection: { id: ship.id, kind: "ship", label: ship.name },
      focusSelection: { kind: "ship", id: ship.id },
      focusMode: "follow",
    }));
  const stations = player.assetRegistry.stationIds
    .map((stationId) => gmStore.stations.find((station) => station.id === stationId))
    .filter((station): station is NonNullable<typeof station> => station != null)
    .sort((left, right) => left.label.localeCompare(right.label))
    .map<BrowserItem>((station) => ({
      key: `owned-station-${station.id}`,
      label: station.label,
      subtitle: `${station.systemId} · ${titleCase(station.category)}`,
      meta: `${station.installedModules.length} modules`,
      selection: { id: station.id, kind: "station", label: station.label },
      focusSelection: { kind: "station", id: station.id },
      focusMode: "tactical",
    }));
  const fleets = player.fleets
    .slice()
    .sort((left, right) => left.label.localeCompare(right.label))
    .map<BrowserItem>((fleet) => ({
      key: `fleet-${fleet.id}`,
      label: fleet.label,
      subtitle: `${titleCase(fleet.role)} · ${titleCase(fleet.status)}`,
      meta: `${fleet.assetIds.length} assets`,
    }));

  return [
    {
      key: "owned-fleets",
      label: "Fleets",
      count: fleets.length,
      items: fleets,
    },
    {
      key: "owned-stations",
      label: "Stations",
      count: stations.length,
      items: stations,
    },
    {
      key: "owned-ships",
      label: "Ships",
      count: ships.length,
      items: ships,
    },
  ];
}

const filteredSections = computed(() => {
  const search = normalize(searchText.value);
  const sections = activeTab.value === "visible" ? buildVisibleSections() : buildOwnedSections();
  return sections
    .map((section) => ({
      ...section,
      items: section.items.filter((item) => matchesSearch(item, search)),
    }))
    .filter((section) => section.items.length > 0);
});

function selectItem(item: BrowserItem) {
  if (!item.selection) {
    return;
  }

  selectionStore.selectSelection(item.selection, "ui");
}

function focusItem(item: BrowserItem) {
  if (item.selection) {
    selectionStore.selectSelection(item.selection, "ui");
  }
  if (item.focusSelection) {
    emit("focus", item.focusSelection, item.focusMode);
  }
}

function isSelected(item: BrowserItem) {
  return !!item.selection
    && item.selection.id === selectedEntityId.value
    && item.selection.kind === selectedEntityKind.value;
}
</script>

<template>
  <section class="entity-browser-panel pointer-events-auto">
    <div class="entity-browser-panel__header">
      <div>
        <div class="entity-browser-panel__kicker">Tactical View</div>
        <h3>Entities</h3>
      </div>
      <div class="entity-browser-panel__context">
        <span>{{ activeSystemId ?? "Galaxy" }}</span>
        <span>{{ povLevel }}</span>
      </div>
    </div>

    <div class="entity-browser-panel__tabs">
      <button
        type="button"
        class="entity-browser-panel__tab"
        :class="activeTab === 'visible' ? 'entity-browser-panel__tab--active' : ''"
        @click="activeTab = 'visible'"
      >
        Visible
      </button>
      <button
        type="button"
        class="entity-browser-panel__tab"
        :class="activeTab === 'owned' ? 'entity-browser-panel__tab--active' : ''"
        @click="activeTab = 'owned'"
      >
        Owned
      </button>
    </div>

    <input
      v-model="searchText"
      class="entity-browser-panel__search"
      type="text"
      placeholder="Filter entities"
    >

    <div v-if="activeTab === 'owned' && !playerFaction" class="entity-browser-panel__empty">
      No player-owned assets yet.
    </div>
    <div v-else-if="filteredSections.length === 0" class="entity-browser-panel__empty">
      Nothing matches the current view.
    </div>
    <div v-else class="entity-browser-panel__sections">
      <section
        v-for="section in filteredSections"
        :key="section.key"
        class="entity-browser-section"
      >
        <header class="entity-browser-section__header">
          <span>{{ section.label }}</span>
          <span>{{ section.items.length }}</span>
        </header>
        <div class="entity-browser-section__items">
          <div
            v-for="item in section.items"
            :key="item.key"
            class="entity-browser-item"
            :class="isSelected(item) ? 'entity-browser-item--selected' : ''"
          >
            <button
              type="button"
              class="entity-browser-item__body"
              :disabled="!item.selection"
              @click="selectItem(item)"
            >
              <div class="entity-browser-item__label">{{ item.label }}</div>
              <div class="entity-browser-item__subtitle">{{ item.subtitle }}</div>
              <div v-if="item.meta" class="entity-browser-item__meta">{{ item.meta }}</div>
            </button>
            <button
              v-if="item.focusSelection"
              type="button"
              class="entity-browser-item__focus"
              @click.stop="focusItem(item)"
            >
              Focus
            </button>
          </div>
        </div>
      </section>
    </div>
  </section>
</template>
