import type { CollectionEntry } from "astro:content";

export type GlossaryEntry = CollectionEntry<"glossaire">;

export type GlossaryPortalLink = {
  href: string;
  label: string;
};

export type GlossaryRelationSection = {
  title: string;
  items: GlossaryEntry[];
};

export type GlossaryRelationBlock = GlossaryRelationSection & {
  className: string;
};

export type GlossaryHomeStats = {
  totalEntries: number;
  paradigmesCount: number;
  doctrinesCount: number;
  metaRegimesCount: number;
};

export type GlossaryEntryAsideData = {
  displayFamily: string;
  displayDomain: string;
  displayLevel: string;
  showNoyau: boolean;
  showSameFamily: boolean;
  fondamentaux: GlossaryEntry[];
  sameFamilyTitle: string;
  sameFamilyEntries: GlossaryEntry[];
  relationSections: GlossaryRelationSection[];
  contextualTheory: GlossaryEntry[];
};

export type GlossaryHomeData = {
  fondamentaux: GlossaryEntry[];
  scenes: GlossaryEntry[];
  dynamiques: GlossaryEntry[];
  metaRegimes: GlossaryEntry[];
  metaRegimesPreview: GlossaryEntry[];
  arcalite?: GlossaryEntry;
  cratialite?: GlossaryEntry;
  tension?: GlossaryEntry;
  sceneDepreuve?: GlossaryEntry;
  archicration?: GlossaryEntry;
};

export const GLOSSARY_COLLATOR = new Intl.Collator("fr", {
  sensitivity: "base",
  numeric: true,
});

export const FAMILY_LABELS: Record<string, string> = {
  "concept-fondamental": "Concept fondamental",
  scene: "Scène",
  dynamique: "Dynamique",
  pathologie: "Pathologie",
  topologie: "Topologie",
  "meta-regime": "Méta-régime",
  paradigme: "Paradigme",
  doctrine: "Doctrine",
  verbe: "Verbe",
  "dispositif-ia": "Dispositif IA",
  "tension-irreductible": "Tension irréductible",
  figure: "Figure",
  qualification: "Qualification",
  epistemologie: "Épistémologie",
};

export const KIND_LABELS: Record<string, string> = {
  concept: "Concept",
  diagnostic: "Diagnostic",
  topologie: "Topologie",
  verbe: "Verbe",
  paradigme: "Paradigme",
  doctrine: "Doctrine",
  dispositif: "Dispositif",
  figure: "Figure",
  qualification: "Qualification",
  epistemologie: "Épistémologie",
};

export const DOMAIN_LABELS: Record<string, string> = {
  transversal: "Transversal",
  theorie: "Théorie",
  "cas-ia": "Cas IA",
};

export const LEVEL_LABELS: Record<string, string> = {
  fondamental: "Fondamental",
  intermediaire: "Intermédiaire",
  avance: "Avancé",
};

export const FONDAMENTAUX_WANTED = [
  "archicratie",
  "arcalite",
  "cratialite",
  "archicration",
  "co-viabilite",
  "tension",
] as const;

export const FAMILY_SECTION_TITLES: Record<string, string> = {
  "concept-fondamental": "Noyau archicratique",
  scene: "Scènes archicratiques",
  dynamique: "Dynamiques archicratiques",
  pathologie: "Pathologies archicratiques",
  topologie: "Topologies voisines",
  "meta-regime": "Méta-régimes archicratiques",
  paradigme: "Paradigmes voisins",
  doctrine: "Doctrines fondatrices",
  verbe: "Verbes de la scène",
  "dispositif-ia": "Dispositifs IA",
  "tension-irreductible": "Tensions irréductibles",
  figure: "Figures archicratiques",
  qualification: "Qualifications archicratiques",
  epistemologie: "Outillage épistémologique",
};

const PREFERRED_PARADIGME_SLUGS = [
  "gouvernementalite",
  "gouvernementalite-algorithmique",
  "cybernetique",
  "biopolitique",
  "domination-legale-rationnelle",
  "democratie-deliberative",
  "gouvernance-des-communs",
  "agencement-machinique",
  "pharmacologie-technique",
  "preemption-algorithmique",
  "dissensus-politique",
  "lieu-vide-du-pouvoir",
  "habitus-et-violence-symbolique",
  "theorie-de-la-resonance",
  "conatus-et-multitude",
  "configuration-et-interdependance",
  "technodiversite-et-cosmotechnie",
  "grammatisation-et-proletarisation-cognitive",
] as const;

const PREFERRED_DOCTRINE_SLUGS = [
  "contractualisme-hobbesien",
  "droit-naturel-et-propriete",
  "volonte-generale",
  "decisionnisme-souverain",
] as const;

export function normalizeGlossarySlug(value: unknown): string {
  return String(value ?? "")
    .trim()
    .replace(/^\/+|\/+$/g, "")
    .replace(/\.(md|mdx)$/i, "")
    .toLowerCase();
}

export function slugOfGlossaryEntry(
  entry: Pick<GlossaryEntry, "id"> | null | undefined,
): string {
  return normalizeGlossarySlug(entry?.id ?? "");
}

export function hrefOfGlossaryEntry(
  entry: Pick<GlossaryEntry, "id"> | null | undefined,
): string {
  const slug = slugOfGlossaryEntry(entry);
  return slug ? `/glossaire/${slug}/` : "/glossaire/";
}

export function buildGlossaryBySlug(
  entries: GlossaryEntry[] = [],
): Map<string, GlossaryEntry> {
  return new Map(entries.map((entry) => [slugOfGlossaryEntry(entry), entry]));
}

export function sortGlossaryEntries(
  entries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  return [...entries].sort((a, b) =>
    GLOSSARY_COLLATOR.compare(a.data.term, b.data.term),
  );
}

export function uniqueGlossaryEntries(
  entries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  const seen = new Set<string>();
  const out: GlossaryEntry[] = [];

  for (const entry of entries) {
    const slug = slugOfGlossaryEntry(entry);
    if (!slug || seen.has(slug)) continue;
    seen.add(slug);
    out.push(entry);
  }

  return out;
}

export function resolveGlossaryEntriesInSourceOrder(
  slugs: string[] = [],
  allEntries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  const bySlug = buildGlossaryBySlug(allEntries);
  const seen = new Set<string>();
  const resolved: GlossaryEntry[] = [];

  for (const rawSlug of slugs) {
    const slug = normalizeGlossarySlug(rawSlug);
    if (!slug || seen.has(slug)) continue;

    const entry = bySlug.get(slug);
    if (!entry) continue;

    seen.add(slug);
    resolved.push(entry);
  }

  return resolved;
}

export function resolveGlossaryEntries(
  slugs: string[] = [],
  allEntries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  return sortGlossaryEntries(
    resolveGlossaryEntriesInSourceOrder(slugs, allEntries),
  );
}

export function rawFamilyOf(
  entry: GlossaryEntry | null | undefined,
): string {
  return String(entry?.data?.family ?? "");
}

export function kindOf(
  entry: GlossaryEntry | null | undefined,
): string {
  return String(entry?.data?.kind ?? "");
}

export function familyOf(
  entry: GlossaryEntry | null | undefined,
): string {
  const explicit = rawFamilyOf(entry);
  if (explicit) return explicit;

  const slug = slugOfGlossaryEntry(entry);
  const kind = kindOf(entry);

  if (kind === "paradigme") return "paradigme";
  if (kind === "doctrine") return "doctrine";
  if (kind === "verbe") return "verbe";

  if (slug === "scene-depreuve") return "scene";
  if (slug === "autarchicratie") return "pathologie";
  if (slug === "obliteration-archicratique") return "dynamique";

  if (
    FONDAMENTAUX_WANTED.includes(
      slug as (typeof FONDAMENTAUX_WANTED)[number],
    )
  ) {
    return "concept-fondamental";
  }

  if (slug === "archicrations-differentielles-et-formes-hybrides") {
    return "topologie";
  }

  if (kind === "topologie" && slug.startsWith("archicrations-")) {
    return "meta-regime";
  }

  return "";
}

export function getDisplayFamily(
  entry: GlossaryEntry | null | undefined,
): string {
  const familyKey = rawFamilyOf(entry) || familyOf(entry);
  return FAMILY_LABELS[familyKey] ?? KIND_LABELS[kindOf(entry)] ?? "Fiche";
}

export function getDisplayDomain(
  entry: GlossaryEntry | null | undefined,
): string {
  const key = String(entry?.data?.domain ?? "");
  return key ? (DOMAIN_LABELS[key] ?? key) : "";
}

export function getDisplayLevel(
  entry: GlossaryEntry | null | undefined,
): string {
  const key = String(entry?.data?.level ?? "");
  return key ? (LEVEL_LABELS[key] ?? key) : "";
}

export function getFondamentaux(
  entries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  const bySlug = buildGlossaryBySlug(entries);

  return sortGlossaryEntries(
    FONDAMENTAUX_WANTED
      .map((slug) => bySlug.get(slug))
      .filter(Boolean) as GlossaryEntry[],
  );
}

export function getGlossaryEntriesByFamily(
  entries: GlossaryEntry[] = [],
  familyKey: string,
): GlossaryEntry[] {
  return sortGlossaryEntries(
    entries.filter((entry) => familyOf(entry) === familyKey),
  );
}

export function countGlossaryEntriesByKind(
  entries: GlossaryEntry[] = [],
  kindKey: string,
): number {
  return entries.filter((entry) => kindOf(entry) === kindKey).length;
}

export function countGlossaryEntriesByFamily(
  entries: GlossaryEntry[] = [],
  familyKey: string,
): number {
  return entries.filter((entry) => familyOf(entry) === familyKey).length;
}

export function getGlossaryPortalLinks(): GlossaryPortalLink[] {
  return [
    { href: "/glossaire/", label: "Accueil du glossaire" },
    { href: "/glossaire/concepts-fondamentaux/", label: "Concepts fondamentaux" },
    { href: "/glossaire/index-complet/", label: "Index complet" },
    {
      href: "/glossaire/paradigme-archicratique/",
      label: "Paradigme archicratique",
    },
    {
      href: "/glossaire/scenes-archicratiques/",
      label: "Scènes archicratiques",
    },
    {
      href: "/glossaire/dynamiques-archicratiques/",
      label: "Dynamiques archicratiques",
    },
    {
      href: "/glossaire/tensions-irreductibles/",
      label: "Tensions irréductibles",
    },
    {
      href: "/glossaire/archicrations/",
      label: "Méta-régimes archicratiques",
    },
    { href: "/glossaire/paradigmes/", label: "Paradigmes et doctrines" },
    { href: "/glossaire/verbes-de-la-scene/", label: "Verbes de la scène" },
  ];
}

export function getGlossaryHomeStats(
  allEntries: GlossaryEntry[] = [],
): GlossaryHomeStats {
  return {
    totalEntries: allEntries.length,
    paradigmesCount: countGlossaryEntriesByKind(allEntries, "paradigme"),
    doctrinesCount: countGlossaryEntriesByKind(allEntries, "doctrine"),
    metaRegimesCount: countGlossaryEntriesByFamily(allEntries, "meta-regime"),
  };
}

export function getEntriesOfSameFamily(
  entry: GlossaryEntry,
  allEntries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  const familyKey = familyOf(entry);
  if (!familyKey) return [];

  if (familyKey === "concept-fondamental") {
    return getFondamentaux(allEntries);
  }

  return getGlossaryEntriesByFamily(allEntries, familyKey);
}

export function getSameFamilyTitle(
  entry: GlossaryEntry,
): string {
  return FAMILY_SECTION_TITLES[familyOf(entry)] ?? "Même famille";
}

export function getRelationBlocks(
  entry: GlossaryEntry,
  allEntries: GlossaryEntry[] = [],
): GlossaryRelationBlock[] {
  const currentSlug = slugOfGlossaryEntry(entry);

  const relatedEntries = resolveGlossaryEntriesInSourceOrder(
    entry.data.related ?? [],
    allEntries,
  ).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);

  const opposedEntries = resolveGlossaryEntriesInSourceOrder(
    entry.data.opposedTo ?? [],
    allEntries,
  ).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);

  const seeAlsoEntries = resolveGlossaryEntriesInSourceOrder(
    entry.data.seeAlso ?? [],
    allEntries,
  ).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);

  return [
    {
      title: "Concepts liés",
      items: relatedEntries,
      className: "is-related",
    },
    {
      title: "En tension avec",
      items: opposedEntries,
      className: "is-opposed",
    },
    {
      title: "Voir aussi",
      items: seeAlsoEntries,
      className: "is-see-also",
    },
  ].filter((block) => block.items.length > 0);
}

export function getRelationSections(
  entry: GlossaryEntry,
  allEntries: GlossaryEntry[] = [],
): GlossaryRelationSection[] {
  return getRelationBlocks(entry, allEntries).map(({ title, items }) => ({
    title,
    items,
  }));
}

function isTheoryEntry(entry: GlossaryEntry): boolean {
  const familyKey = familyOf(entry);
  const kindKey = kindOf(entry);

  return (
    familyKey === "paradigme" ||
    familyKey === "doctrine" ||
    kindKey === "paradigme" ||
    kindKey === "doctrine"
  );
}

export function getContextualTheory(
  entry: GlossaryEntry,
  allEntries: GlossaryEntry[] = [],
): GlossaryEntry[] {
  const currentSlug = slugOfGlossaryEntry(entry);
  const bySlug = buildGlossaryBySlug(allEntries);

  const fromRelations = uniqueGlossaryEntries([
    ...resolveGlossaryEntriesInSourceOrder(entry.data.related ?? [], allEntries),
    ...resolveGlossaryEntriesInSourceOrder(entry.data.seeAlso ?? [], allEntries),
    ...resolveGlossaryEntriesInSourceOrder(entry.data.opposedTo ?? [], allEntries),
  ])
    .filter((item) => slugOfGlossaryEntry(item) !== currentSlug)
    .filter((item) => isTheoryEntry(item));

  if (fromRelations.length > 0) {
    return fromRelations.slice(0, 6);
  }

  if (familyOf(entry) === "paradigme") {
    return uniqueGlossaryEntries(
      PREFERRED_PARADIGME_SLUGS
        .filter((slug) => slug !== currentSlug)
        .map((slug) => bySlug.get(slug))
        .filter(Boolean) as GlossaryEntry[],
    ).slice(0, 8);
  }

  if (familyOf(entry) === "doctrine") {
    return uniqueGlossaryEntries(
      PREFERRED_DOCTRINE_SLUGS
        .filter((slug) => slug !== currentSlug)
        .map((slug) => bySlug.get(slug))
        .filter(Boolean) as GlossaryEntry[],
    ).slice(0, 6);
  }

  return [];
}

export function getGlossaryEntryAsideData(
  currentEntry: GlossaryEntry,
  allEntries: GlossaryEntry[] = [],
): GlossaryEntryAsideData {
  const currentFamily = familyOf(currentEntry);
  const fondamentaux = getFondamentaux(allEntries);
  const sameFamilyEntries = getEntriesOfSameFamily(currentEntry, allEntries);
  const sameFamilyTitle = getSameFamilyTitle(currentEntry);
  const relationSections = getRelationSections(currentEntry, allEntries);
  const contextualTheory = getContextualTheory(currentEntry, allEntries);

  const showNoyau =
    currentFamily !== "concept-fondamental" &&
    fondamentaux.length > 0;

  const showSameFamily =
    currentFamily !== "concept-fondamental" &&
    sameFamilyEntries.length > 0;

  return {
    displayFamily: getDisplayFamily(currentEntry),
    displayDomain: getDisplayDomain(currentEntry),
    displayLevel: getDisplayLevel(currentEntry),
    showNoyau,
    showSameFamily,
    fondamentaux,
    sameFamilyTitle,
    sameFamilyEntries: showSameFamily ? sameFamilyEntries : [],
    relationSections,
    contextualTheory,
  };
}

export function getGlossaryHomeData(
  entries: GlossaryEntry[] = [],
): GlossaryHomeData {
  const bySlug = buildGlossaryBySlug(entries);

  const fondamentaux = getGlossaryEntriesByFamily(entries, "concept-fondamental");
  const scenes = getGlossaryEntriesByFamily(entries, "scene");
  const dynamiques = sortGlossaryEntries(
    entries.filter((entry) =>
      ["dynamique", "pathologie"].includes(familyOf(entry)),
    ),
  );
  const metaRegimes = getGlossaryEntriesByFamily(entries, "meta-regime");

  return {
    fondamentaux,
    scenes,
    dynamiques,
    metaRegimes,
    metaRegimesPreview: metaRegimes.slice(0, 6),
    arcalite: bySlug.get("arcalite"),
    cratialite: bySlug.get("cratialite"),
    tension: bySlug.get("tension"),
    sceneDepreuve: bySlug.get("scene-depreuve"),
    archicration: bySlug.get("archicration"),
  };
}
