/**
 * DocListFilters — client-side filter/sort/search controls for the homepage.
 *
 * Receives the full list of docs (with summaries) from the server component,
 * renders filter bar + filtered grid. URL params stay simple — state is local.
 */
"use client";
import Link from "next/link";
import { useEffect, useMemo, useRef, useState } from "react";

interface ChunkHit {
  chunk_id: string;
  doc_id: string;
  page: number;
  type: string;
  snippet: string;
  score: number;
  href: string;
  classification?: string | null;
}

interface Doc {
  id: string;
  title: string;
  pages: number;
  collection: string;
  classification: string;
  summary: string;
}

type Sort = "collection" | "title" | "pages" | "classification";

const CLASSIFICATION_RANK: Record<string, number> = {
  "TOP SECRET//NOFORN": 6,
  "TOP SECRET": 5,
  SECRET: 4,
  CONFIDENTIAL: 3,
  RESTRICTED: 2,
  CUI: 2,
  UNCLASSIFIED: 1,
  "—": 0,
};

const CLASSIFICATION_COLOR: Record<string, string> = {
  "TOP SECRET": "#ff3344",
  SECRET: "#ff6b6b",
  CONFIDENTIAL: "#ff8a4d",
  RESTRICTED: "#ffa500",
  CUI: "#ffd23f",
  UNCLASSIFIED: "#5a6678",
};

function classColor(c: string): string {
  const base = c.split("//")[0].trim();
  return CLASSIFICATION_COLOR[base] ?? "#5a6678";
}

function escapeHtml(s: string): string {
  return s
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#x27;");
}

export function DocListFilters({ docs }: { docs: Doc[] }) {
  const [q, setQ] = useState("");
  const [collection, setCollection] = useState<string>("all");
  const [classification, setClassification] = useState<string>("all");
  const [sort, setSort] = useState<Sort>("collection");
  const [chunkHits, setChunkHits] = useState<ChunkHit[]>([]);
  const [chunkLoading, setChunkLoading] = useState(false);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const requestIdRef = useRef(0);

  // Hybrid (BM25 + dense + RRF) search over the chunk corpus.
  // Local title/summary filter runs instantly above; this surfaces matches
  // inside the body text via /api/search/hybrid.
  useEffect(() => {
    const term = q.trim();
    if (debounceRef.current) clearTimeout(debounceRef.current);
    if (term.length < 3) {
      setChunkHits([]);
      setChunkLoading(false);
      return;
    }
    setChunkLoading(true);
    debounceRef.current = setTimeout(() => {
      const myReq = ++requestIdRef.current;
      // rerank=0 → skip the cross-encoder (5-30s on CPU). RRF score is good
      // enough for the homepage browser; /search page can still use rerank.
      fetch(`/api/search/hybrid?q=${encodeURIComponent(term)}&top_k=12&rerank=0`)
        .then((r) => (r.ok ? r.json() : { hits: [] }))
        .then((data: { hits?: ChunkHit[] }) => {
          if (myReq !== requestIdRef.current) return; // stale
          setChunkHits(data.hits ?? []);
        })
        .catch(() => {
          if (myReq === requestIdRef.current) setChunkHits([]);
        })
        .finally(() => {
          if (myReq === requestIdRef.current) setChunkLoading(false);
        });
    }, 280);
    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, [q]);

  const collections = useMemo(
    () => Array.from(new Set(docs.map((d) => d.collection))).sort(),
    [docs],
  );
  const classifications = useMemo(
    () => Array.from(new Set(docs.map((d) => d.classification))).sort(),
    [docs],
  );

  const filtered = useMemo(() => {
    let out = docs;
    if (q.trim()) {
      const ql = q.toLowerCase();
      out = out.filter(
        (d) =>
          d.title.toLowerCase().includes(ql) ||
          d.id.toLowerCase().includes(ql) ||
          d.summary.toLowerCase().includes(ql),
      );
    }
    if (collection !== "all") out = out.filter((d) => d.collection === collection);
    if (classification !== "all") out = out.filter((d) => d.classification === classification);

    out = [...out].sort((a, b) => {
      switch (sort) {
        case "title":
          return a.title.localeCompare(b.title);
        case "pages":
          return b.pages - a.pages;
        case "classification":
          return (
            (CLASSIFICATION_RANK[b.classification.split("//")[0]] ?? 0) -
            (CLASSIFICATION_RANK[a.classification.split("//")[0]] ?? 0)
          );
        case "collection":
        default:
          return a.collection.localeCompare(b.collection) || a.title.localeCompare(b.title);
      }
    });
    return out;
  }, [docs, q, collection, classification, sort]);

  // Group by collection only when sort === collection
  const grouped = useMemo(() => {
    if (sort !== "collection") return [["__all", filtered] as const];
    const map = new Map<string, Doc[]>();
    for (const d of filtered) {
      if (!map.has(d.collection)) map.set(d.collection, []);
      map.get(d.collection)!.push(d);
    }
    return Array.from(map.entries());
  }, [filtered, sort]);

  return (
    <div>
      <div className="mb-8 p-3 border border-[rgba(0,255,156,0.15)] bg-[#0a121e] rounded flex flex-wrap items-end gap-3">
        <div className="flex-1 min-w-[240px]">
          <label className="font-mono text-[10px] uppercase tracking-widest text-[#5a6678] block mb-1 flex items-center gap-2">
            <span>buscar (título · resumo · corpo dos documentos)</span>
            {chunkLoading && <span className="text-[#00ff9c]">⟳ buscando…</span>}
          </label>
          <input
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="ex. Olathe, Hoover, esfera, Tic Tac, Nimitz..."
            className="w-full bg-transparent border border-[rgba(0,255,156,0.20)] focus:border-[#00ff9c] rounded px-2 py-1.5 font-mono text-sm text-[#c8d4e6] outline-none"
          />
        </div>
        <div>
          <label className="font-mono text-[10px] uppercase tracking-widest text-[#5a6678] block mb-1">
            coleção
          </label>
          <select
            value={collection}
            onChange={(e) => setCollection(e.target.value)}
            className="bg-[#0a121e] border border-[rgba(0,255,156,0.20)] focus:border-[#00ff9c] rounded px-2 py-1.5 font-mono text-xs text-[#c8d4e6] outline-none"
          >
            <option value="all">todas</option>
            {collections.map((c) => (
              <option key={c} value={c}>
                {c}
              </option>
            ))}
          </select>
        </div>
        <div>
          <label className="font-mono text-[10px] uppercase tracking-widest text-[#5a6678] block mb-1">
            classificação
          </label>
          <select
            value={classification}
            onChange={(e) => setClassification(e.target.value)}
            className="bg-[#0a121e] border border-[rgba(0,255,156,0.20)] focus:border-[#00ff9c] rounded px-2 py-1.5 font-mono text-xs text-[#c8d4e6] outline-none"
          >
            <option value="all">todas</option>
            {classifications.map((c) => (
              <option key={c} value={c}>
                {c}
              </option>
            ))}
          </select>
        </div>
        <div>
          <label className="font-mono text-[10px] uppercase tracking-widest text-[#5a6678] block mb-1">
            ordenar
          </label>
          <select
            value={sort}
            onChange={(e) => setSort(e.target.value as Sort)}
            className="bg-[#0a121e] border border-[rgba(0,255,156,0.20)] focus:border-[#00ff9c] rounded px-2 py-1.5 font-mono text-xs text-[#c8d4e6] outline-none"
          >
            <option value="collection">coleção</option>
            <option value="title">título A→Z</option>
            <option value="pages">+ páginas</option>
            <option value="classification">classificação</option>
          </select>
        </div>
        <div className="font-mono text-xs text-[#5a6678] ml-auto">
          {filtered.length}/{docs.length}
        </div>
      </div>

      {q.trim().length >= 3 && (chunkHits.length > 0 || chunkLoading) && (
        <section className="mb-10 p-4 border border-[rgba(127,219,255,0.20)] rounded bg-[rgba(127,219,255,0.03)]">
          <header className="flex items-baseline justify-between mb-3 border-b border-[rgba(127,219,255,0.20)] pb-2">
            <h2 className="font-mono text-sm text-[#7fdbff] uppercase tracking-widest">
              ▍ trechos encontrados no corpo dos documentos
            </h2>
            <span className="font-mono text-[10px] text-[#5a6678]">
              hybrid: BM25 + dense embeddings + reranker
              {chunkHits.length > 0 && <> · {chunkHits.length} resultados</>}
            </span>
          </header>
          {chunkLoading && chunkHits.length === 0 && (
            <p className="font-mono text-xs text-[#5a6678]">buscando nos {docs.reduce((s, d) => s + d.pages, 0)} pages…</p>
          )}
          <ul className="space-y-2">
            {chunkHits.map((h) => {
              const docTitle = docs.find((d) => d.id === h.doc_id)?.title ?? h.doc_id;
              const cls = (h.classification ?? "").split("//")[0].trim();
              const clsColor = CLASSIFICATION_COLOR[cls] ?? "#5a6678";
              return (
                <li key={`${h.doc_id}-${h.chunk_id}`}>
                  <Link
                    href={h.href}
                    className="block p-3 bg-[#060a13] border border-[rgba(127,219,255,0.12)] hover:border-[#00ff9c] rounded transition"
                  >
                    <div className="flex items-center gap-2 mb-1 font-mono text-[10px] uppercase tracking-widest">
                      {cls && (
                        <span style={{ color: clsColor, borderColor: clsColor }} className="border px-1.5 py-0.5 rounded">
                          {cls}
                        </span>
                      )}
                      <span className="text-[#7fdbff]">{h.chunk_id}</span>
                      <span className="text-[#5a6678]">· p{h.page} · {h.type}</span>
                      <span className="ml-auto text-[#00ff9c]">score {h.score.toFixed(3)}</span>
                    </div>
                    <div className="text-[13px] text-[#c8d4e6] leading-snug mb-1">
                      {h.snippet || <span className="text-[#5a6678] italic">sem texto</span>}
                    </div>
                    <div className="font-mono text-[10px] text-[#8896aa] truncate">↳ {docTitle}</div>
                  </Link>
                </li>
              );
            })}
          </ul>
        </section>
      )}

      {grouped.map(([key, items]) => (
        <section key={key} className="mb-10">
          {sort === "collection" && (
            <h2 className="font-mono text-sm text-[#7fdbff] uppercase tracking-widest mb-4 border-l-2 border-[#7fdbff] pl-3">
              {key.replace(/-/g, " ")} <span className="text-[#5a6678]">({items.length})</span>
            </h2>
          )}
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-6 gap-4 auto-rows-min">
            {items.map((d) => {
              const color = classColor(d.classification);
              // Bento sizing — varied tile widths based on pitch length + classification weight
              const pitchLen = d.summary?.length ?? 0;
              const classRank = CLASSIFICATION_RANK[d.classification.split("//")[0]] ?? 0;
              const isBig = pitchLen > 500 || (classRank >= 5 && d.pages >= 50);
              const isMedium = pitchLen > 280;
              const span =
                isBig
                  ? "lg:col-span-3 md:col-span-2"
                  : isMedium
                    ? "lg:col-span-2 md:col-span-1"
                    : "lg:col-span-2 md:col-span-1";
              return (
                <Link
                  key={d.id}
                  href={`/d/${d.id}`}
                  className={`${span} group block p-4 border-2 rounded transition-all relative overflow-hidden
                             border-[rgba(0,255,156,0.12)] hover:border-[#00ff9c]
                             bg-gradient-to-br from-[#0a121e] to-[#060a13]
                             hover:from-[rgba(0,255,156,0.06)] hover:to-[#060a13]
                             flex flex-col`}
                  style={{
                    boxShadow: `inset 0 0 0 1px ${color}10`,
                  }}
                >
                  {/* Decorative classification stripe on left edge */}
                  <span
                    className="absolute left-0 top-0 bottom-0 w-1 opacity-60 group-hover:opacity-100 transition"
                    style={{ background: color }}
                  />

                  <div className="flex items-center gap-2 mb-2 pl-2">
                    <span
                      className="font-mono text-[10px] uppercase tracking-widest font-bold"
                      style={{ color }}
                    >
                      {d.classification}
                    </span>
                    <span className="font-mono text-[10px] text-[#5a6678]">· {d.pages}p</span>
                  </div>

                  <div className="text-base text-[#c8d4e6] font-medium leading-snug pl-2 mb-3">
                    {d.title}
                  </div>

                  {d.summary && (
                    <p
                      className="text-[13px] text-[#a8b8cc] leading-relaxed pl-2 flex-1 whitespace-pre-line"
                      // Render basic markdown bold from pitch (e.g. **text**)
                      dangerouslySetInnerHTML={{
                        __html: escapeHtml(d.summary)
                          .replace(/\*\*([^*]+)\*\*/g, '<strong class="text-[#c8d4e6]">$1</strong>')
                          .replace(/_([^_]+)_/g, '<em>$1</em>'),
                      }}
                    />
                  )}

                  <div className="flex items-center justify-between mt-3 pl-2 pt-2 border-t border-[rgba(0,255,156,0.08)]">
                    <div className="font-mono text-[10px] text-[#5a6678] truncate flex-1">{d.id}</div>
                    <span className="font-mono text-[10px] text-[#7fdbff] opacity-0 group-hover:opacity-100 transition ml-2">
                      →
                    </span>
                  </div>
                </Link>
              );
            })}
          </div>
        </section>
      ))}

      {filtered.length === 0 && (
        <div className="text-center font-mono text-sm text-[#5a6678] py-12">
          nenhum documento corresponde aos filtros
        </div>
      )}
    </div>
  );
}
