/**
 * Universal frontmatter renderer.
 *
 * Introspects ANY entity/doc/page/etc. frontmatter and renders each field with
 * its semantic UI primitive. The schema (CLAUDE-schema-full.md) IS the contract.
 *
 * Grouping strategy (in order):
 *   IDENTITY        canonical_name, *_id, aliases, disambiguation_note
 *   CLASSIFICATION  highest_classification, classification_markings, language_detected, content_classification
 *   METRICS         total_mentions, documents_count, page_count, totals, qualities
 *   RELATIONS       primary_*, key_entities, observed_in_event, observers, related, ...
 *   EVIDENCE        redactions, signatures_observed, tables_detected, images_detected
 *   TEMPORAL        date_start/end, dates, last_*
 *   SPATIAL         coordinates, primary_location
 *   ENRICHMENT      enrichment_status, external_sources, verified_facts
 *   FLAGS           flags
 */
import {
  Users, Building2, MapPin, CalendarRange, Disc3, Plane, Crosshair, BookOpen,
  Files, Image as ImageIcon, Table2, Eye, AlertTriangle, FileSearch,
  FileWarning, Stamp, PenSquare, Bookmark, Hash, Layers, Zap,
} from "lucide-react";
import { FmWikiLink, FmWikiLinkList } from "./fm/wikilink";
import {
  FmConfidence, FmClassification, FmEnrichmentBadge, FmContentChip,
  FmPageTypeChip, FmLanguageChip, FmChip, FmStat, FmCoordinates,
  FmQualityDot, FmFlag, FmTimestamp,
} from "./fm/badges";
import { FmBboxThumb } from "./fm/bbox-thumb";
import { FmExternalSources } from "./fm/external-sources";
import type { AnyFrontmatter, EntityRef, EntitiesExtracted } from "@/lib/fm-types";

interface Props {
  fm: AnyFrontmatter;
  /** Page-derived context — needed for bbox thumbnails to know which PNG to slice. */
  pageCtx?: { docId: string; pageNum: number };
}

function isNonEmptyArray(x: unknown): x is unknown[] {
  return Array.isArray(x) && x.length > 0;
}

/** Maps a class key under entities_extracted to its proper /e/<folder>/<id> namespace. */
const ENTITY_NS: Record<keyof EntitiesExtracted, { label: string; ns: string; icon: React.ReactNode }> = {
  people:        { label: "People",        ns: "people",        icon: <Users size={11} /> },
  organizations: { label: "Organizations", ns: "org",           icon: <Building2 size={11} /> },
  locations:     { label: "Locations",     ns: "loc",           icon: <MapPin size={11} /> },
  events:        { label: "Events",        ns: "event",         icon: <CalendarRange size={11} /> },
  uap_objects:   { label: "UAP Objects",   ns: "uap",           icon: <Disc3 size={11} /> },
  vehicles:      { label: "Vehicles",      ns: "vehicle",       icon: <Plane size={11} /> },
  operations:    { label: "Operations",    ns: "op",            icon: <Crosshair size={11} /> },
  concepts:      { label: "Concepts",      ns: "concept",       icon: <BookOpen size={11} /> },
};

/** Render an entity ref (extracted from a page) as a wiki-link.
 *  Uses the entity's `name` slugified — best-effort. */
function entityRefToLink(ref: EntityRef, ns: string): string {
  const name = ref.name ?? "";
  if (!name) return "";
  const id = name
    .normalize("NFD")
    .replace(/[̀-ͯ]/g, "")
    .toLowerCase()
    .replace(/[^a-z0-9-]+/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-|-$/g, "");
  return `${ns}/${id}`;
}

function Section({
  title, icon, count, children,
}: { title: string; icon?: React.ReactNode; count?: number; children: React.ReactNode }) {
  return (
    <section>
      <h3 className="font-mono text-[10px] text-[#8896aa] uppercase tracking-widest mb-2 flex items-center gap-1.5">
        {icon}
        <span>{title}</span>
        {count !== undefined && <span className="text-[#5a6678]">({count})</span>}
      </h3>
      {children}
    </section>
  );
}

export function FrontmatterPanel({ fm, pageCtx }: Props) {
  const sections: React.ReactNode[] = [];

  /* ── CLASSIFICATION BANNER (top, prominent) ───────────────── */
  const markings = fm.classification_markings ?? [];
  const hasMarkings = markings.length > 0 || fm.highest_classification;
  if (hasMarkings) {
    sections.push(
      <Section key="cls" title="Classification" icon={<Bookmark size={12} className="text-[#ff3344]" />}>
        <div className="flex flex-wrap gap-1.5">
          {fm.highest_classification && (
            <FmClassification level={fm.highest_classification} caveats={undefined} />
          )}
          {markings.map((m, i) => (
            <FmClassification key={i} level={m.level} caveats={m.caveats} />
          ))}
        </div>
      </Section>
    );
  }

  /* ── ALIASES ──────────────────────────────────────────────── */
  if (isNonEmptyArray(fm.aliases)) {
    sections.push(
      <Section key="aliases" title="Aliases" icon={<Hash size={12} />}>
        <div className="flex flex-wrap gap-1">
          {(fm.aliases as string[]).slice(0, 16).map((a, i) => (
            <span key={i} className="font-mono text-[10px] text-[#7fdbff] bg-[rgba(127,219,255,0.06)] border border-[rgba(127,219,255,0.32)] rounded px-1.5 py-0.5">
              {a}
            </span>
          ))}
        </div>
      </Section>
    );
  }

  /* ── DISAMBIGUATION ───────────────────────────────────────── */
  if (fm.disambiguation_note) {
    sections.push(
      <Section key="disamb" title="Disambiguation" icon={<AlertTriangle size={12} className="text-[#f5c542]" />}>
        <p className="text-sm text-[#f5c542] border-l-2 border-[#f5c542] pl-3">{fm.disambiguation_note}</p>
      </Section>
    );
  }

  /* ── CONTENT & PAGE TYPE ──────────────────────────────────── */
  const cc = (fm.content_classification ?? []) as string[];
  const wantsContent = cc.length > 0 || fm.page_type || fm.language_detected || isNonEmptyArray(fm.languages_detected);
  if (wantsContent) {
    sections.push(
      <Section key="content" title="Content" icon={<FileSearch size={12} />}>
        <div className="flex flex-wrap gap-1.5 items-center">
          {fm.page_type && <FmPageTypeChip type={fm.page_type} />}
          {cc.map((k, i) => <FmContentChip key={i} kind={k as Parameters<typeof FmContentChip>[0]["kind"]} />)}
          {fm.language_detected && <FmLanguageChip code={fm.language_detected} />}
          {(fm.languages_detected ?? []).map((l, i) => <FmLanguageChip key={i} code={l} />)}
        </div>
      </Section>
    );
  }

  /* ── METRICS ──────────────────────────────────────────────── */
  const metrics: React.ReactNode[] = [];
  if (typeof fm.total_mentions === "number") metrics.push(<FmStat key="m1" icon={<Hash size={9} />} label="mentions" value={fm.total_mentions} color="cyan" />);
  if (typeof fm.documents_count === "number") metrics.push(<FmStat key="m2" icon={<Files size={9} />} label="documents" value={fm.documents_count} color="cyan" />);
  if (typeof fm.page_count === "number")     metrics.push(<FmStat key="m3" icon={<Files size={9} />} label="pages" value={fm.page_count} color="amber" />);
  if (typeof fm.total_redactions === "number" && fm.total_redactions > 0) metrics.push(<FmStat key="m4" icon={<FileWarning size={9} />} label="redactions" value={fm.total_redactions} color="red" />);
  if (typeof fm.total_signatures === "number" && fm.total_signatures > 0) metrics.push(<FmStat key="m5" icon={<PenSquare size={9} />} label="signatures" value={fm.total_signatures} color="violet" />);
  if (typeof fm.total_tables === "number" && fm.total_tables > 0) metrics.push(<FmStat key="m6" icon={<Table2 size={9} />} label="tables" value={fm.total_tables} color="cyan" />);
  if (typeof fm.total_images === "number" && fm.total_images > 0) metrics.push(<FmStat key="m7" icon={<ImageIcon size={9} />} label="images" value={fm.total_images} color="cyan" />);
  if (typeof fm.ocr_quality_score === "number") metrics.push(<FmStat key="m8" icon={<Zap size={9} />} label="ocr" value={`${Math.round(fm.ocr_quality_score * 100)}%`} color="soft" />);
  if (typeof fm.vision_quality_score === "number") metrics.push(<FmStat key="m9" icon={<Eye size={9} />} label="vision" value={`${Math.round(fm.vision_quality_score * 100)}%`} color="soft" />);
  if (metrics.length > 0) {
    sections.push(
      <Section key="metrics" title="Stats" icon={<Layers size={12} />}>
        <div className="flex flex-wrap gap-2">{metrics}</div>
      </Section>
    );
  }

  /* ── KEY ENTITIES (document-level rollup) ─────────────────── */
  if (fm.key_entities) {
    const ke = fm.key_entities as EntitiesExtracted;
    for (const k of Object.keys(ENTITY_NS) as Array<keyof EntitiesExtracted>) {
      const refs = ke[k] ?? [];
      if (!isNonEmptyArray(refs)) continue;
      const meta = ENTITY_NS[k];
      const links = (refs as EntityRef[]).map((r) => entityRefToLink(r, meta.ns)).filter(Boolean);
      sections.push(
        <Section key={`ke-${k}`} title={`Key ${meta.label}`} icon={meta.icon} count={refs.length}>
          <FmWikiLinkList items={links} size="sm" />
        </Section>
      );
    }
  }

  /* ── ENTITIES EXTRACTED (page-level) ──────────────────────── */
  if (fm.entities_extracted) {
    const ee = fm.entities_extracted as EntitiesExtracted;
    for (const k of Object.keys(ENTITY_NS) as Array<keyof EntitiesExtracted>) {
      const refs = ee[k] ?? [];
      if (!isNonEmptyArray(refs)) continue;
      const meta = ENTITY_NS[k];
      const links = (refs as EntityRef[]).map((r) => entityRefToLink(r, meta.ns)).filter(Boolean);
      sections.push(
        <Section key={`ee-${k}`} title={meta.label} icon={meta.icon} count={refs.length}>
          <FmWikiLinkList items={links} size="xs" />
        </Section>
      );
    }
  }

  /* ── EVIDENCE: redactions ─────────────────────────────────── */
  if (isNonEmptyArray(fm.redactions)) {
    sections.push(
      <Section key="redactions" title="Redactions" icon={<FileWarning size={12} className="text-[#ff3344]" />} count={fm.redactions!.length}>
        <div className="flex flex-wrap gap-2">
          {fm.redactions!.map((r, i) => (
            <div key={i} className="flex items-center gap-2 border border-[rgba(255,51,68,0.32)] bg-[rgba(255,51,68,0.04)] rounded p-1.5">
              <FmBboxThumb bbox={r.bbox} docId={pageCtx?.docId} pageNum={pageCtx?.pageNum} width={64} height={48} label={r.description} />
              <div className="text-[10px] font-mono">
                <div className="text-[#ff3344] font-semibold">{r.code ?? "REDACTED"}</div>
                {r.description && <div className="text-[#8896aa] max-w-[160px] truncate">{r.description}</div>}
              </div>
            </div>
          ))}
        </div>
      </Section>
    );
  }

  /* ── EVIDENCE: signatures ─────────────────────────────────── */
  if (isNonEmptyArray(fm.signatures_observed)) {
    sections.push(
      <Section key="sigs" title="Signatures" icon={<PenSquare size={12} className="text-[#bb6bd9]" />} count={fm.signatures_observed!.length}>
        <div className="flex flex-wrap gap-2">
          {fm.signatures_observed!.map((s, i) => (
            <div key={i} className="flex items-center gap-2 border border-[rgba(187,107,217,0.32)] bg-[rgba(187,107,217,0.04)] rounded p-1.5">
              <FmBboxThumb bbox={s.bbox} docId={pageCtx?.docId} pageNum={pageCtx?.pageNum} width={64} height={48} />
              <div className="text-[10px] font-mono">
                <div className="text-[#bb6bd9] font-semibold">{s.signer_inferred ?? "unknown signer"}</div>
                <FmConfidence band={s.confidence_band} />
                {s.notes && <div className="text-[#8896aa] max-w-[160px] truncate">{s.notes}</div>}
              </div>
            </div>
          ))}
        </div>
      </Section>
    );
  }

  /* ── EVIDENCE: tables ─────────────────────────────────────── */
  if (isNonEmptyArray(fm.tables_detected)) {
    sections.push(
      <Section key="tabs" title="Tables on this page" icon={<Table2 size={12} className="text-[#1e9eb5]" />} count={fm.tables_detected!.length}>
        <div className="flex flex-wrap gap-2">
          {fm.tables_detected!.map((t, i) => (
            <div key={i} className="flex items-center gap-2 border border-[rgba(30,158,181,0.32)] bg-[rgba(30,158,181,0.04)] rounded p-1.5">
              <FmBboxThumb bbox={t.bbox} docId={pageCtx?.docId} pageNum={pageCtx?.pageNum} width={64} height={48} />
              <div className="text-[10px] font-mono">
                {t.table_id ? <FmWikiLink target={`table/${t.table_id}`} size="xs" /> : <span className="text-[#1e9eb5]">inline table</span>}
                <div className="text-[#8896aa] mt-1">
                  {t.col_count_estimate ?? "?"}×{t.row_count_estimate ?? "?"}
                  {t.spans_multi_page && <span className="text-[#f5c542] ml-1">multi-page</span>}
                </div>
                {t.headers_summary && <div className="text-[#5a6678] max-w-[160px] truncate">{t.headers_summary}</div>}
              </div>
            </div>
          ))}
        </div>
      </Section>
    );
  }

  /* ── EVIDENCE: images detected ────────────────────────────── */
  if (isNonEmptyArray(fm.images_detected)) {
    sections.push(
      <Section key="imgs" title="Images on this page" icon={<ImageIcon size={12} className="text-[#ffeb99]" />} count={fm.images_detected!.length}>
        <div className="flex flex-wrap gap-2">
          {fm.images_detected!.map((im, i) => (
            <div key={i} className="flex items-center gap-2 border border-[rgba(255,235,153,0.32)] bg-[rgba(255,235,153,0.04)] rounded p-1.5">
              <FmBboxThumb bbox={im.bbox} docId={pageCtx?.docId} pageNum={pageCtx?.pageNum} width={64} height={64} />
              <div className="text-[10px] font-mono">
                <div className="text-[#ffeb99] font-semibold">{im.image_type ?? "image"}</div>
                {im.caption_ocr && <div className="text-[#8896aa] max-w-[160px]">{im.caption_ocr}</div>}
              </div>
            </div>
          ))}
        </div>
      </Section>
    );
  }

  /* ── UAP OBSERVATION ──────────────────────────────────────── */
  if (fm.uap_observation_fields) {
    const u = fm.uap_observation_fields;
    sections.push(
      <Section key="uap" title="UAP Observation" icon={<Disc3 size={12} className="text-[#ff3344]" />}>
        <div className="flex flex-wrap gap-2">
          {u.shape && <FmChip color="red" icon={<Disc3 size={9} />} label={`shape: ${u.shape}`} />}
          {u.color && <FmChip color="red" label={`color: ${u.color}`} />}
          {u.size_estimate && <FmChip color="red" label={`size: ${u.size_estimate}`} />}
          {u.altitude_ft !== null && u.altitude_ft !== undefined && <FmChip color="cyan" label={`alt: ${u.altitude_ft} ft`} />}
          {u.speed_kts !== null && u.speed_kts !== undefined && <FmChip color="cyan" label={`speed: ${u.speed_kts} kts`} />}
          {u.bearing_deg !== null && u.bearing_deg !== undefined && <FmChip color="cyan" label={`bearing: ${u.bearing_deg}°`} />}
          {u.distance_nm !== null && u.distance_nm !== undefined && <FmChip color="cyan" label={`dist: ${u.distance_nm} nm`} />}
          {u.duration_seconds && <FmChip color="cyan" label={`duration: ${u.duration_seconds}s`} />}
          {u.coordinates && <FmCoordinates lat={u.coordinates.lat ?? undefined} lon={u.coordinates.lon ?? undefined} raw={u.coordinates.raw_text} />}
        </div>
      </Section>
    );
  }

  /* ── UAP-OBJECT specific fields (entity-level) ────────────── */
  if (fm.entity_class === "uap_object") {
    const u = fm;
    sections.push(
      <Section key="uapent" title="Object profile" icon={<Disc3 size={12} className="text-[#ff3344]" />}>
        <div className="flex flex-wrap gap-2">
          {u.shape && <FmChip color="red" label={`shape: ${u.shape}`} />}
          {u.color && <FmChip color="red" label={`color: ${u.color}`} />}
          {u.size_estimate_m && <FmChip color="red" label={`size: ${u.size_estimate_m.min ?? "?"}–${u.size_estimate_m.max ?? "?"} m`} />}
          {u.altitude_ft && <FmChip color="cyan" label={`alt: ${u.altitude_ft.min ?? "?"}–${u.altitude_ft.max ?? "?"} ft`} />}
          {u.speed_kts && <FmChip color="cyan" label={`speed: ${u.speed_kts.min ?? "?"}–${u.speed_kts.max ?? "?"} kts`} />}
          {isNonEmptyArray(u.maneuver_descriptors) && u.maneuver_descriptors!.map((m, i) => <FmChip key={i} color="violet" label={m} />)}
          {isNonEmptyArray(u.features) && u.features!.map((f, i) => <FmChip key={`f${i}`} color="amber" label={f} />)}
          {u.confidence_band_overall && <FmConfidence band={u.confidence_band_overall} />}
        </div>
        {u.observed_in_event && (
          <div className="mt-2 text-[10px] text-[#5a6678] font-mono">observed in: <FmWikiLink target={u.observed_in_event} size="xs" /></div>
        )}
      </Section>
    );
  }

  /* ── LOCATION specific ────────────────────────────────────── */
  if (fm.entity_class === "location") {
    sections.push(
      <Section key="loc" title="Location" icon={<MapPin size={12} className="text-[#3fde6a]" />}>
        <div className="flex flex-wrap gap-2 items-center">
          {fm.location_type && <FmChip color="green" label={fm.location_type} />}
          {fm.country && <FmChip color="soft" label={Array.isArray(fm.country) ? fm.country.join(", ") : fm.country} />}
          {fm.region && <FmChip color="soft" label={fm.region} />}
          {fm.coordinates && (
            <FmCoordinates lat={fm.coordinates.lat ?? undefined} lon={fm.coordinates.lon ?? undefined} raw={fm.coordinates.raw_text} />
          )}
          {fm.parent_location && <FmWikiLink target={fm.parent_location} size="xs" />}
        </div>
      </Section>
    );
  }

  /* ── EVENT specific ───────────────────────────────────────── */
  if (fm.entity_class === "event") {
    sections.push(
      <Section key="evt" title="Event" icon={<CalendarRange size={12} className="text-[#ffa500]" />}>
        <div className="flex flex-wrap gap-2 items-center">
          {fm.event_class && <FmChip color="amber" label={fm.event_class} />}
          {fm.date_start && <FmChip color="amber" label={`from: ${fm.date_start}`} />}
          {fm.date_end && fm.date_end !== fm.date_start && <FmChip color="amber" label={`to: ${fm.date_end}`} />}
          {fm.date_confidence && <FmConfidence band={fm.date_confidence} />}
          {fm.primary_location && <FmWikiLink target={fm.primary_location} size="xs" />}
          {isNonEmptyArray(fm.observers) && fm.observers!.map((o, i) => <FmWikiLink key={`o${i}`} target={o} size="xs" />)}
          {isNonEmptyArray(fm.uap_objects) && fm.uap_objects!.map((u, i) => <FmWikiLink key={`u${i}`} target={u} size="xs" />)}
        </div>
      </Section>
    );
  }

  /* ── PERSON specific ──────────────────────────────────────── */
  if (fm.entity_class === "person") {
    const dates = fm.dates ?? {};
    sections.push(
      <Section key="psn" title="Person" icon={<Users size={12} className="text-[#ff6ec7]" />}>
        <div className="flex flex-wrap gap-2 items-center">
          {fm.primary_role && <FmChip color="violet" label={fm.primary_role} />}
          {fm.primary_organization && <FmChip color="amber" label={fm.primary_organization} />}
          {isNonEmptyArray(fm.roles) && fm.roles!.map((r, i) => <FmChip key={i} color="violet" label={r} />)}
          {(dates.born || dates.died) && (
            <FmChip color="soft" label={`${dates.born ?? "?"} — ${dates.died ?? "?"}`} />
          )}
        </div>
      </Section>
    );
  }

  /* ── ORGANIZATION specific ────────────────────────────────── */
  if (fm.entity_class === "organization") {
    sections.push(
      <Section key="org" title="Organization" icon={<Building2 size={12} className="text-[#ff8a4d]" />}>
        <div className="flex flex-wrap gap-2 items-center">
          {fm.organization_type && <FmChip color="amber" label={fm.organization_type} />}
          {fm.country && <FmChip color="soft" label={Array.isArray(fm.country) ? fm.country.join(", ") : fm.country} />}
          {fm.founded && <FmChip color="soft" label={`founded: ${fm.founded}`} />}
        </div>
      </Section>
    );
  }

  /* ── CONCEPT/VEHICLE/OPERATION quick chips ────────────────── */
  if (fm.entity_class === "concept") {
    sections.push(
      <Section key="cncpt" title="Concept" icon={<BookOpen size={12} className="text-[#06d6a0]" />}>
        <div className="flex flex-wrap gap-2 items-center">
          {fm.concept_class && <FmChip color="green" label={fm.concept_class} />}
          {fm.domain && <FmChip color="soft" label={fm.domain} />}
        </div>
        {fm.definition_short && <p className="text-sm text-[#c8d4e6] mt-2">{fm.definition_short}</p>}
        {fm.definition_short_pt_br && <p className="text-xs text-[#8896aa] mt-1 italic">{fm.definition_short_pt_br}</p>}
      </Section>
    );
  }

  /* ── ENRICHMENT ───────────────────────────────────────────── */
  if (fm.enrichment_status || isNonEmptyArray(fm.external_sources)) {
    sections.push(
      <Section key="enr" title="Enrichment" icon={<Stamp size={12} />}>
        <div className="flex items-center gap-2 mb-1">
          <FmEnrichmentBadge status={fm.enrichment_status} />
          {fm.last_enriched && <FmTimestamp value={fm.last_enriched} label="last" />}
        </div>
        <FmExternalSources sources={fm.external_sources} />
      </Section>
    );
  }

  /* ── FLAGS ────────────────────────────────────────────────── */
  if (isNonEmptyArray(fm.flags)) {
    sections.push(
      <Section key="flags" title="Flags" icon={<AlertTriangle size={12} className="text-[#f5c542]" />}>
        <div className="flex flex-wrap gap-1">
          {fm.flags!.map((f, i) => <FmFlag key={i} flag={f} />)}
        </div>
      </Section>
    );
  }

  /* ── TIMESTAMPS (compact footer) ──────────────────────────── */
  const ts: React.ReactNode[] = [];
  if (fm.last_ingest)   ts.push(<FmTimestamp key="li" value={fm.last_ingest} label="ingest" />);
  if (fm.last_lint)     ts.push(<FmTimestamp key="ll" value={fm.last_lint} label="lint" />);
  if (fm.last_enriched && !fm.external_sources) ts.push(<FmTimestamp key="le" value={fm.last_enriched} label="enriched" />);

  return (
    <div className="space-y-5">
      {sections}
      {ts.length > 0 && (
        <div className="flex flex-wrap gap-3 pt-2 border-t border-[rgba(0,255,156,0.08)]">{ts}</div>
      )}
    </div>
  );
}
