import { ref } from "vue";
import { defineStore } from "pinia";
import * as api from "@/api/canonicalSystems";
import type { CanonicalSystem, MappingProposal } from "@/api/canonicalSystems";
import { useToastStore } from "@/stores/toast";
import { apiErrorMessage } from "@/api/client";

/**
 * The global area catalog (milestone 307). Shared by every project, so it is
 * fetched ONCE per session rather than per project — the whole point of the
 * table is that it is the same list everywhere.
 */
export const useCanonicalSystemsStore = defineStore("canonicalSystems", () => {
  const catalog = ref<CanonicalSystem[]>([]);
  const loaded = ref(false);
  const loading = ref(false);
  const proposalsByProject = ref<Record<number, MappingProposal[]>>({});

  async function fetchCatalog(force = false) {
    if (loaded.value && !force) return catalog.value;
    loading.value = true;
    try {
      catalog.value = await api.listCanonicalSystems();
      loaded.value = true;
    } catch {
      // A naming aid must never break the screen it rides on — an empty
      // catalog degrades the suggestion, it does not fail the form.
      catalog.value = [];
    } finally {
      loading.value = false;
    }
    return catalog.value;
  }

  function byId(id: number | null): CanonicalSystem | undefined {
    if (id == null) return undefined;
    return catalog.value.find((c) => c.id === id);
  }

  async function fetchProposals(projectId: number) {
    proposalsByProject.value[projectId] = await api.proposeMappings(projectId);
    return proposalsByProject.value[projectId];
  }

  /** Apply or clear one mapping, then drop it from the pending proposals. */
  async function mapSystem(projectId: number, systemId: number, canonicalId: number | null) {
    try {
      await api.mapSystem(systemId, canonicalId);
    } catch (e) {
      useToastStore().show(apiErrorMessage(e, "Failed to map system"), "error");
      throw e;
    }
    dismissProposal(projectId, systemId);
  }

  /** Remove a proposal from the pending list without writing anything. */
  function dismissProposal(projectId: number, systemId: number) {
    const list = proposalsByProject.value[projectId];
    if (list) {
      proposalsByProject.value[projectId] = list.filter((p) => p.system_id !== systemId);
    }
  }

  async function createEntry(data: { name: string; description?: string }) {
    const entry = await api.createCanonicalSystem(data);
    catalog.value.push(entry);
    return entry;
  }

  async function updateEntry(
    id: number,
    data: Partial<{ name: string; description: string; order_index: number }>,
  ) {
    const entry = await api.updateCanonicalSystem(id, data);
    const idx = catalog.value.findIndex((c) => c.id === id);
    if (idx >= 0) catalog.value[idx] = entry;
    return entry;
  }

  return {
    catalog,
    loaded,
    loading,
    proposalsByProject,
    fetchCatalog,
    byId,
    fetchProposals,
    mapSystem,
    dismissProposal,
    createEntry,
    updateEntry,
  };
});
