// ── Receipts list ─────────────────────────────────────────────────────────────

const _CHAIN_COLORS_FALLBACK = { bg: "#9ca3af", text: "#fff" };
let _chainColorsCache = null;

function useChainColors() {
  const [colors, setColors] = React.useState(_chainColorsCache);
  React.useEffect(() => {
    if (_chainColorsCache) return;
    fetch("/api/chains")
      .then((r) => r.json())
      .then(({ chains }) => {
        const map = {};
        chains.forEach(({ name, bg, text }) => {
          map[name] = { bg, text };
        });
        _chainColorsCache = map;
        setColors(map);
      })
      .catch(() => {});
  }, []);
  return colors;
}

function ChainBadge({ chain, colors }) {
  const color = (colors && colors[chain]) || _CHAIN_COLORS_FALLBACK;
  return (
    <span
      style={{ backgroundColor: color.bg, color: color.text }}
      className="text-2xs px-1 py-0 rounded font-medium uppercase tracking-wide text-[10px]"
    >
      {chain}
    </span>
  );
}

// phase: null | 'uploading' | 'pending' | 'processing' | 'done' | 'error'
const JOB_LABELS = {
  uploading: "Caricamento…",
  pending: "In coda…",
  processing: "OCR in corso…",
  done: "Fatto!",
};

function UploadPdf({ onUploaded }) {
  const [dragging, setDragging] = React.useState(false);
  const [phase, setPhase] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [receiptId, setReceiptId] = React.useState(null);
  const inputRef = React.useRef();
  const pollRef = React.useRef(null);

  function stopPolling() {
    if (pollRef.current) {
      clearInterval(pollRef.current);
      pollRef.current = null;
    }
  }

  async function pollJob(filename) {
    stopPolling();
    pollRef.current = setInterval(async () => {
      try {
        const r = await fetch(`/api/jobs/${filename}`);
        if (!r.ok) {
          stopPolling();
          setPhase("error");
          setError(`Operazione non trovata`);
          return;
        }
        const job = await r.json();
        setPhase(job.status);
        if (job.status === "done") {
          stopPolling();
          setReceiptId(job.id);
          onUploaded && onUploaded(job.id);
        } else if (job.status === "error") {
          stopPolling();
          setError(job.error || "OCR fallito");
        }
      } catch (e) {
        stopPolling();
        setPhase("error");
        setError(String(e));
      }
    }, 1500);
  }

  async function upload(file) {
    if (!file || !file.name.toLowerCase().endsWith(".pdf")) {
      setPhase("error");
      setError("Sono accettati solo file PDF.");
      return;
    }
    setPhase("uploading");
    setError(null);
    const fd = new FormData();
    fd.append("file", file);
    try {
      const r = await fetch("/api/upload-pdf", { method: "POST", body: fd });
      const json = await r.json();
      if (!r.ok) {
        setPhase("error");
        setError(json.detail || `Error ${r.status}`);
        return;
      }
      setPhase("pending");
      pollJob(json.filename);
    } catch (e) {
      setPhase("error");
      setError(String(e));
    }
  }

  function reset() {
    stopPolling();
    setPhase(null);
    setError(null);
    setReceiptId(null);
  }

  function onDrop(e) {
    e.preventDefault();
    setDragging(false);
    upload(e.dataTransfer.files[0]);
  }

  const busy =
    phase === "uploading" || phase === "pending" || phase === "processing";
  const isDone = phase === "done";

  return (
    <div className="mb-4">
      <div
        onDragOver={(e) => {
          e.preventDefault();
          if (!busy) setDragging(true);
        }}
        onDragLeave={() => setDragging(false)}
        onDrop={(e) => {
          if (!busy) onDrop(e);
        }}
        onClick={() => {
          if (isDone) {
            if (receiptId) window.location.hash = `#/receipts/${receiptId}`;
          } else if (!busy) {
            reset();
            inputRef.current.click();
          }
        }}
        className={`border-2 border-dashed rounded-xl px-4 py-5 text-center transition-colors select-none
          ${
            busy
              ? "cursor-wait border-gray-200 bg-gray-50"
              : isDone
                ? "cursor-pointer border-green-300 bg-green-50"
                : dragging
                  ? "cursor-pointer border-[#2d7a3a] bg-green-50"
                  : "cursor-pointer border-gray-300 hover:border-gray-400 bg-white"
          }`}
      >
        <input
          ref={inputRef}
          type="file"
          accept=".pdf"
          className="hidden"
          onChange={(e) => {
            upload(e.target.files[0]);
            e.target.value = "";
          }}
        />

        {busy && (
          <div className="flex flex-col items-center gap-2">
            <div className="flex gap-1.5 items-center">
              {["uploading", "pending", "processing"].map((s) => (
                <React.Fragment key={s}>
                  <span
                    className={`text-xs font-medium px-2 py-0.5 rounded-full transition-colors
                    ${phase === s ? "bg-[#2d7a3a] text-white" : "bg-gray-100 text-gray-400"}`}
                  >
                    {JOB_LABELS[s]}
                  </span>
                  {s !== "processing" && (
                    <span className="text-gray-300 text-xs">›</span>
                  )}
                </React.Fragment>
              ))}
            </div>
          </div>
        )}
        {isDone && (
          <p className="text-sm text-green-700 font-medium">
            Scontrino elaborato —{" "}
            {receiptId && (
              <a
                href={`#/receipts/${receiptId}`}
                className="underline font-semibold"
              >
                vedi scontrino
              </a>
            )}
            {receiptId && " · "}
            <span
              className="cursor-pointer underline"
              onClick={(e) => {
                e.stopPropagation();
                reset();
              }}
            >
              carica un altro
            </span>
          </p>
        )}
        {phase === "error" && <p className="text-sm text-red-500">{error}</p>}
        {!phase && (
          <p className="text-sm text-gray-400">
            Trascina un PDF qui, o{" "}
            <span className="text-[#2d7a3a] font-medium">seleziona</span>
          </p>
        )}
      </div>
    </div>
  );
}

function _getChainFromHash() {
  const hash = window.location.hash;
  const q = hash.indexOf("?");
  if (q === -1) return "all";
  return new URLSearchParams(hash.slice(q + 1)).get("chain") || "all";
}

function _setChainInHash(chain) {
  const base = "#/receipts";
  const next =
    chain === "all" ? base : `${base}?chain=${encodeURIComponent(chain)}`;
  if (window.location.hash !== next) history.replaceState(null, "", next);
}

const PAGE_SIZE = 20;

function _receiptYearMonth(r) {
  if (r.receipt_at) return r.receipt_at.slice(0, 7);
  if (r.date && r.date.includes("/")) {
    const [, m, y] = r.date.split("/");
    return `${y}-${m.padStart(2, "0")}`;
  }
  return null;
}

function _monthLabel(ym) {
  const [y, m] = ym.split("-");
  const d = new Date(parseInt(y, 10), parseInt(m, 10) - 1);
  return `${d.toLocaleString("it-IT", { month: "long" })} ${y}`;
}

function ReceiptsList() {
  const [data, setData] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [chain, setChain] = React.useState(_getChainFromHash);
  const [page, setPage] = React.useState(1);
  const [refreshKey, setRefreshKey] = React.useState(0);
  const colors = useChainColors();

  React.useEffect(() => {
    const h = () => {
      const next = _getChainFromHash();
      setChain((prev) => {
        if (prev !== next) setPage(1);
        return next;
      });
    };
    window.addEventListener("hashchange", h);
    return () => window.removeEventListener("hashchange", h);
  }, []);

  function handleChainChange(c) {
    _setChainInHash(c);
    setChain(c);
    setPage(1);
  }

  React.useEffect(() => {
    setData(null);
    const params = new URLSearchParams({ page, limit: PAGE_SIZE });
    if (chain !== "all") params.set("chain", chain);
    fetch(`/api/receipts?${params}`)
      .then((r) => (r.ok ? r.json() : Promise.reject(r.status)))
      .then(setData)
      .catch((e) => setError(String(e)));
  }, [refreshKey, chain, page]);

  if (error) return <p className="text-sm text-red-500 p-4">Errore: {error}</p>;
  if (!data)
    return (
      <p className="text-sm text-gray-400 p-8 text-center">
        Caricamento scontrini…
      </p>
    );

  const chains = ["all", ...data.chains];
  const totalPages = Math.ceil(data.total / PAGE_SIZE);

  let lastYM = null;

  return (
    <div>
      <div className="flex items-center justify-between mb-3">
        <h1 className="text-xl font-bold">
          Scontrini{" "}
          <span className="text-sm text-gray-400 font-normal">
            ({data.total})
          </span>
        </h1>
        <div className="flex gap-2">
          <button
            onClick={() => {
              window.location.hash = "#/new-receipt";
            }}
            className="text-sm px-3 py-1.5 rounded-lg bg-[#2d7a3a] text-white font-medium hover:bg-[#236130] transition-colors"
          >
            + Aggiungi scontrino
          </button>
        </div>
      </div>

      {/* Chain filter pills */}
      <div className="flex flex-wrap gap-1.5 mb-4">
        {chains.map((c) => {
          const color =
            c === "all"
              ? null
              : (colors && colors[c]) || _CHAIN_COLORS_FALLBACK;
          const active = chain === c;
          return (
            <button
              key={c}
              onClick={() => handleChainChange(c)}
              style={
                active && color
                  ? { backgroundColor: color.bg, color: color.text }
                  : {}
              }
              className={`px-3 py-1 rounded-full text-sm font-medium transition-colors capitalize
                ${
                  active
                    ? color
                      ? ""
                      : "bg-gray-800 text-white"
                    : "bg-white text-gray-600 hover:bg-gray-100"
                }`}
            >
              {c === "all" ? "Tutti" : c === "unknown" ? "Altri" : c}
            </button>
          );
        })}
      </div>

      <div className="space-y-3">
        {data.receipts.map((r) => {
          const ym = _receiptYearMonth(r);
          const showSep = ym && ym !== lastYM;
          lastYM = ym;
          return (
            <React.Fragment key={r.id}>
              {showSep && (
                <div className="pt-1 pb-0.5 px-1">
                  <span className="text-xs font-semibold text-gray-400 uppercase tracking-widest">
                    {_monthLabel(ym)}
                  </span>
                </div>
              )}
              <div
                className="relative bg-white rounded-2xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors overflow-hidden"
                onClick={() => {
                  window.location.hash = `#/receipts/${r.id}`;
                }}
              >
                <MatchBorder matched={r.matched} total={r.unique_items} />
                <div className="flex justify-between items-start">
                  <div>
                    <div className="flex items-center gap-2">
                      <span className="font-semibold text-gray-900">
                        {r.store_name}
                      </span>
                    </div>
                    {r.store_address && (
                      <div className="text-xs text-gray-500 mt-0.5">
                        {r.store_address}
                      </div>
                    )}
                    <div className="text-xs text-gray-400 mt-0.5">
                      {r.date} {r.time}
                    </div>
                  </div>
                  <div className="text-right">
                    <div className="font-bold text-gray-900">
                      €{fmt(r.total_eur)}
                    </div>
                    <div className="text-xs text-gray-400">
                      {r.item_count} articoli
                    </div>
                    <div className="flex items-center gap-1 justify-end mt-1">
                      {r.score_avg != null && (
                        <span
                          className="inline-flex items-center justify-center w-6 h-6 rounded-full text-[10px] font-bold text-white flex-shrink-0"
                          style={{
                            background: mediterraneanScoreColor(r.score_avg),
                          }}
                          title={`Score medio: ${r.score_avg}/100 (${r.scored_count} prodotti)`}
                        >
                          {r.score_avg}
                        </span>
                      )}
                      {r.chain && r.chain !== "unknown" && (
                        <ChainBadge chain={r.chain} colors={colors} />
                      )}
                      {r.source === "ocr" && (
                        <span className="text-xs bg-amber-100 text-amber-700 px-1 py-0 rounded font-medium text-[10px]">
                          PDF
                        </span>
                      )}
                      {r.source === "manual" && (
                        <span className="text-xs bg-blue-100 text-blue-700 px-1 py-0 rounded font-medium text-[10px]">
                          Manuale
                        </span>
                      )}
                    </div>
                  </div>
                </div>
              </div>
            </React.Fragment>
          );
        })}
        {data.receipts.length === 0 && (
          <p className="text-sm text-gray-400 text-center py-8">
            Nessuno scontrino{chain !== "all" ? " per questa catena" : ""}.
          </p>
        )}
      </div>

      {totalPages > 1 && (
        <div className="flex items-center justify-between mt-5">
          <button
            onClick={() => setPage((p) => p - 1)}
            disabled={page === 1}
            className="text-sm px-3 py-1.5 rounded-lg border border-gray-200 text-gray-600 font-medium hover:bg-gray-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
          >
            ← Precedente
          </button>
          <span className="text-sm text-gray-400">
            {page} / {totalPages}
          </span>
          <button
            onClick={() => setPage((p) => p + 1)}
            disabled={page === totalPages}
            className="text-sm px-3 py-1.5 rounded-lg border border-gray-200 text-gray-600 font-medium hover:bg-gray-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
          >
            Successivo →
          </button>
        </div>
      )}
    </div>
  );
}
