// ── Shared utilities ──────────────────────────────────────────────────────────

const PAYMENT_SUGGESTIONS = ["Pagamento Contante", "Pagamento Elettronico"];

function todayDMY() {
  const d = new Date();
  return `${String(d.getDate()).padStart(2, "0")}/${String(d.getMonth() + 1).padStart(2, "0")}/${d.getFullYear()}`;
}

function nowHM() {
  const d = new Date();
  return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
}

function useStoreNames() {
  const [storeNames, setStoreNames] = React.useState([]);
  React.useEffect(() => {
    fetch("/api/receipts")
      .then((r) => r.json())
      .then(({ receipts }) => {
        const names = Array.from(
          new Set(receipts.map((r) => r.store_name).filter(Boolean)),
        ).sort();
        setStoreNames(names);
      })
      .catch(() => {});
  }, []);
  return storeNames;
}

function evalPrice(raw) {
  const cleaned = String(raw)
    .replace(/,/g, ".")
    .replace(/[^0-9+\-*/.()\s]/g, "");
  if (!cleaned.trim()) return null;
  try {
    // eslint-disable-next-line no-new-func
    const result = Function('"use strict"; return (' + cleaned + ")")();
    if (typeof result === "number" && isFinite(result))
      return Math.round(result * 100) / 100;
  } catch (_) {}
  return null;
}

// ── Foldable JSON viewer ──────────────────────────────────────────────────────

function JsonNode({ value, depth = 0 }) {
  const [open, setOpen] = React.useState(depth < 2);

  if (value === null) return <span className="text-gray-400">null</span>;
  if (typeof value === "boolean")
    return <span className="text-purple-600">{String(value)}</span>;
  if (typeof value === "number")
    return <span className="text-blue-600">{value}</span>;
  if (typeof value === "string")
    return <span className="text-green-700">"{value}"</span>;

  const isArray = Array.isArray(value);
  const entries = isArray
    ? value.map((v, i) => [i, v])
    : Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
  const [open0, close0] = isArray ? ["[", "]"] : ["{", "}"];

  if (entries.length === 0)
    return (
      <span className="text-gray-500">
        {open0}
        {close0}
      </span>
    );

  const preview = isArray
    ? `${open0} ${entries.length} items ${close0}`
    : `${open0} ${entries
        .slice(0, 3)
        .map(([k]) => k)
        .join(", ")}${entries.length > 3 ? ", …" : ""} ${close0}`;

  return (
    <span>
      <button
        onClick={() => setOpen((o) => !o)}
        className="text-gray-400 hover:text-gray-700 font-mono text-xs mr-0.5 select-none"
      >
        {open ? "▾" : "▸"}
      </button>
      {!open ? (
        <span
          className="text-gray-400 italic text-xs cursor-pointer"
          onClick={() => setOpen(true)}
        >
          {preview}
        </span>
      ) : (
        <>
          <span className="text-gray-500">{open0}</span>
          <div className="ml-4 border-l border-gray-100 pl-2">
            {entries.map(([k, v], i) => (
              <div key={k} className="leading-5">
                {!isArray && (
                  <span className="text-red-700 font-medium">"{k}"</span>
                )}
                {!isArray && <span className="text-gray-500">: </span>}
                <JsonNode value={v} depth={depth + 1} />
                {i < entries.length - 1 && (
                  <span className="text-gray-400">,</span>
                )}
              </div>
            ))}
          </div>
          <span className="text-gray-500">{close0}</span>
        </>
      )}
    </span>
  );
}

// ── Helpers ───────────────────────────────────────────────────────────────────

const CATEGORY_ICON = {
  Beverages: "🥤",
  "Dairy & Eggs": "🥛",
  "Meat & Fish": "🥩",
  "Bakery & Cereals": "🥖",
  "Fruits & Vegetables": "🥦",
  "Pasta, Rice & Grains": "🍝",
  "Ready Meals": "🍲",
  "Condiments & Sauces": "🫙",
  "Snacks & Sweets": "🍫",
  "Frozen Foods": "❄️",
  "Canned & Preserved": "🥫",
  "Personal Care": "🧴",
  Household: "🧹",
  Other: "📦",
  Uncategorized: "❓",
};

function ecoscoreColor(g) {
  return (
    { A: "#1b7340", B: "#56a02a", C: "#d4a017", D: "#c0541a", E: "#9b1c1c" }[
      (g || "").toUpperCase()
    ] || "#999"
  );
}

function nutriscoreColor(g) {
  return (
    { A: "#038141", B: "#85BB2F", C: "#FECB02", D: "#EE8100", E: "#E63312" }[
      (g || "").toUpperCase()
    ] || "#999"
  );
}
function novaColor(g) {
  return (
    { 1: "#4CAF50", 2: "#8BC34A", 3: "#FF9800", 4: "#F44336" }[g] || "#999"
  );
}

function mediterraneanScoreColor(score) {
  if (score == null) return "#999";
  if (score >= 75) return "#2d7a3a";
  if (score >= 50) return "#85BB2F";
  if (score >= 25) return "#EE8100";
  return "#E63312";
}

function fmt(n, decimals = 2) {
  return n == null ? "—" : Number(n).toFixed(decimals);
}

function offImg(off_id) {
  if (!off_id) return null;
  return `/api/image/${encodeURIComponent(off_id)}`;
}

const PLACEHOLDER_IMG =
  "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Crect width='48' height='48' rx='0' fill='%23f3f4f6'/%3E%3Ctext x='50%25' y='54%25' dominant-baseline='middle' text-anchor='middle' font-size='22' fill='%23d1d5db'%3E%F0%9F%9B%92%3C/text%3E%3C/svg%3E";

// ── Shared small components ───────────────────────────────────────────────────

function BarcodeBlock({ code, isWeighted }) {
  if (!code || isWeighted) return null;
  // The EAN13 barcode font requires exactly 13 digits; anything else (e.g.
  const canRenderBarcode = /^\d{13}$/.test(code);
  return (
    <div className="mt-3 pt-3 border-t border-gray-100 flex flex-col items-center gap-1">
      {canRenderBarcode ? (
        <span
          style={{
            fontFamily: "'Libre Barcode EAN13 Text'",
            fontSize: "5rem",
            lineHeight: 1,
          }}
        >
          {code}
        </span>
      ) : (
        <span className="font-mono text-sm text-gray-500">{code}</span>
      )}
    </div>
  );
}

function ScoreBadge({ grade, colorFn, title }) {
  if (
    !grade ||
    grade === "?" ||
    grade.toLowerCase() === "unknown" ||
    grade.toLowerCase() === "not-applicable"
  )
    return null;
  return (
    <span
      className="inline-flex items-center justify-center w-7 h-7 rounded-full text-xs font-bold text-white flex-shrink-0"
      style={{ background: colorFn(grade) }}
      title={title}
    >
      {grade}
    </span>
  );
}

function MatchBorder({ matched, total }) {
  const pct = total > 0 ? matched / total : 0;
  const color = "#2d7a3a";
  return (
    <div
      title={`${matched}/${total} articoli abbinati`}
      style={{
        position: "absolute",
        top: 0,
        right: 0,
        bottom: 0,
        width: 6,
        background: "#e5e7eb",
        borderRadius: "0 1rem 1rem 0",
        overflow: "hidden",
      }}
    >
      <div
        style={{
          position: "absolute",
          bottom: 0,
          width: "100%",
          height: `${pct * 100}%`,
          background: color,
          transition: "height 0.3s",
        }}
      />
    </div>
  );
}

const LEVEL_COLOR = { high: "#e53935", moderate: "#ff9800", low: "#4caf50" };
const LEVEL_LABEL = { high: "Alto", moderate: "Med", low: "Basso" };

function LevelPill({ level }) {
  if (!level) return null;
  return (
    <span
      className="inline-block px-1.5 rounded text-xs font-bold text-white ml-1"
      style={{ background: LEVEL_COLOR[level] || "#bbb" }}
    >
      {LEVEL_LABEL[level] || level}
    </span>
  );
}

function StatusPill({
  value,
  yesLabel,
  noLabel,
  yesColor = "#4caf50",
  noColor = "#e53935",
}) {
  if (!value || value === "unknown") return null;
  const isYes = value === "yes";
  return (
    <span
      className="inline-block px-2 py-0.5 rounded text-xs font-semibold text-white"
      style={{ background: isYes ? yesColor : noColor }}
    >
      {isYes ? yesLabel : noLabel}
    </span>
  );
}

function PanelSection({ title, children }) {
  return (
    <div className="mt-3 pt-3 border-t border-gray-100">
      <div className="text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">
        {title}
      </div>
      {children}
    </div>
  );
}

function ConfirmDialog({
  title,
  message,
  confirmLabel = "Confirm",
  danger = false,
  onConfirm,
  onCancel,
}) {
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4">
      <div className="absolute inset-0 bg-black/40" onClick={onCancel} />
      <div className="relative bg-white rounded-2xl shadow-xl max-w-sm w-full p-6">
        {title && (
          <div className="text-base font-semibold text-gray-900 mb-2">
            {title}
          </div>
        )}
        {message && <p className="text-sm text-gray-500 mb-5">{message}</p>}
        <div className="flex justify-end gap-2">
          <button
            onClick={onCancel}
            className="px-4 py-2 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-100 transition-colors"
          >
            Annulla
          </button>
          <button
            onClick={onConfirm}
            className={`px-4 py-2 rounded-lg text-sm font-medium text-white transition-colors ${
              danger
                ? "bg-red-600 hover:bg-red-700"
                : "bg-[#2d7a3a] hover:bg-[#236130]"
            }`}
          >
            {confirmLabel}
          </button>
        </div>
      </div>
    </div>
  );
}

function MatchInfo({ match }) {
  if (!match)
    return <span className="text-xs text-gray-300 italic">non abbinato</span>;
  const link = match.off_found
    ? `https://world.openfoodfacts.org/product/${match.barcode}`
    : null;
  return (
    <div className="flex items-center gap-1.5 flex-wrap min-w-0">
      <span className="text-sm font-semibold text-[#2d7a3a] truncate">
        {match.product_name || "—"}
      </span>
      {link && (
        <a
          href={link}
          target="_blank"
          className="text-xs text-gray-400 hover:text-[#2d7a3a] underline whitespace-nowrap"
        >
          Open Food Facts ↗
        </a>
      )}
      {match.brands && (
        <span className="text-xs text-gray-400 truncate">{match.brands}</span>
      )}
      {match.quantity && (
        <span className="text-xs text-gray-400 truncate">{match.quantity}</span>
      )}
      {match.suggested_from && (
        <span className="px-1.5 py-0.5 rounded text-xs font-semibold bg-purple-100 text-purple-700 whitespace-nowrap">
          da {match.suggested_from}
        </span>
      )}
    </div>
  );
}
