// ── Barcode scanner overlay ────────────────────────────────────────────────────

function BarcodeScanner({ onScan, onClose }) {
  const videoRef = React.useRef(null);
  React.useEffect(() => {
    const reader = new ZXing.BrowserMultiFormatReader();
    const constraints = { video: { facingMode: { ideal: "environment" } } };
    reader
      .decodeFromConstraints(constraints, videoRef.current, (result, err) => {
        if (result) {
          reader.reset();
          onScan(result.getText());
        }
      })
      .catch((e) => console.error("[scanner]", e));
    return () => reader.reset();
  }, []);
  return (
    <div className="fixed inset-0 bg-black/90 flex flex-col items-center justify-center z-50 gap-4 p-4">
      <p className="text-white text-sm">
        Punta la fotocamera sul codice a barre
      </p>
      <video
        ref={videoRef}
        className="w-full max-w-sm rounded-xl object-cover bg-black"
      />
      <button
        onClick={onClose}
        className="px-4 py-2 rounded-lg border border-white/40 text-white text-sm font-medium active:bg-white/10"
      >
        ✕ Chiudi
      </button>
    </div>
  );
}

// ── Autocomplete input ────────────────────────────────────────────────────────

function AutocompleteInput({ placeholder, value, onChange, field }) {
  const [suggestions, setSuggestions] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const [dropdownStyle, setDropdownStyle] = React.useState({});
  const inputRef = React.useRef(null);
  const debounceRef = React.useRef(null);

  function handleChange(e) {
    const v = e.target.value;
    onChange(v);
    clearTimeout(debounceRef.current);
    if (v.length < 2) {
      setSuggestions([]);
      setOpen(false);
      return;
    }
    debounceRef.current = setTimeout(async () => {
      try {
        const r = await fetch(
          `/api/suggest-off?field=${field}&q=${encodeURIComponent(v)}`,
        );
        const d = await r.json();
        setSuggestions(d.suggestions || []);
        if (inputRef.current) {
          const rect = inputRef.current.getBoundingClientRect();
          setDropdownStyle({
            position: "fixed",
            top: rect.bottom + 4,
            left: rect.left,
            width: rect.width,
            zIndex: 9999,
          });
        }
        setOpen(true);
      } catch {}
    }, 250);
  }

  function pick(s) {
    onChange(s);
    setSuggestions([]);
    setOpen(false);
  }

  return (
    <div className="flex-1 min-w-0">
      <input
        ref={inputRef}
        value={value}
        onChange={handleChange}
        onBlur={() => setTimeout(() => setOpen(false), 150)}
        placeholder={placeholder}
        className="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#2d7a3a]/30 focus:border-[#2d7a3a]"
      />
      {open &&
        suggestions.length > 0 &&
        ReactDOM.createPortal(
          <ul
            style={dropdownStyle}
            className="bg-white border border-gray-200 rounded-lg shadow-lg max-h-48 overflow-y-auto text-sm"
          >
            {suggestions.map((s) => (
              <li
                key={s}
                onMouseDown={() => pick(s)}
                className="px-3 py-2 cursor-pointer hover:bg-gray-50 truncate"
              >
                {s}
              </li>
            ))}
          </ul>,
          document.body,
        )}
    </div>
  );
}

// ── Search widget ─────────────────────────────────────────────────────────────

function SearchWidget({
  itemName,
  chain,
  receiptId,
  onSaved,
  onCancel,
  mongoOk,
}) {
  const [query, setQuery] = React.useState("");
  const [results, setResults] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [debugProduct, setDebugProduct] = React.useState(null);
  const [debugLoading, setDebugLoading] = React.useState(false);
  const [showScanner, setShowScanner] = React.useState(false);
  const [showAdvanced, setShowAdvanced] = React.useState(false);
  const [filterBrand, setFilterBrand] = React.useState("");
  const [filterCategory, setFilterCategory] = React.useState("");

  const [barcodeWarning, setBarcodeWarning] = React.useState(null);
  const [weightedInfo, setWeightedInfo] = React.useState(null);
  const lastRawScan = React.useRef(null);

  const _BARCODE_TYPE_LABELS = {
    weighted:
      "Articolo pesato/prezzato in negozio — nessun prodotto globale esiste per questo codice",
    periodical:
      "Questo è una rivista/periodico (ISSN), non un prodotto alimentare",
    book: "Questo è un libro (ISBN), non un prodotto alimentare",
    coupon: "Questo è un codice coupon, non un prodotto",
  };

  function looksLikeBarcode(q) {
    return /^\d{7,14}$/.test(q.trim());
  }

  async function fetchBarcodeInfo(code) {
    const r = await fetch(
      `/api/parse-barcode?code=${encodeURIComponent(code.trim())}`,
    );
    return r.json();
  }

  React.useEffect(() => {
    if (debugProduct) {
      document.body.style.overflow = "hidden";
      return () => {
        document.body.style.overflow = "";
      };
    }
  }, [debugProduct]);

  async function openDebug(p) {
    setDebugLoading(true);
    setDebugProduct({ product_name: p.product_name, _loading: true });
    try {
      const r = await fetch(
        `/api/product-raw/${encodeURIComponent(p.barcode)}`,
      );
      setDebugProduct(await r.json());
    } catch (e) {
      setDebugProduct(p);
    } finally {
      setDebugLoading(false);
    }
  }

  React.useEffect(() => {
    fetch(
      `/api/clean-name?name=${encodeURIComponent(itemName)}&chain=${encodeURIComponent(chain)}`,
    )
      .then((r) => r.json())
      .then((d) => setQuery(d.cleaned || itemName))
      .catch(() => setQuery(itemName));
  }, []);

  function handleScan(code) {
    setShowScanner(false);
    lastRawScan.current = code;
    setQuery(code);
    doSearch(code);
  }

  async function doSearch(q) {
    const isBarcode = q.trim() && looksLikeBarcode(q);
    if (!mongoOk && !isBarcode) return;
    const hasFilters = filterBrand || filterCategory;
    if (!q.trim() && !hasFilters) return;
    setLoading(true);
    setError(null);
    setBarcodeWarning(null);
    setWeightedInfo(null);
    try {
      let url;
      if (q.trim() && looksLikeBarcode(q)) {
        lastRawScan.current = q.trim();
        const info = await fetchBarcodeInfo(q);
        if (!info.ok) {
          setBarcodeWarning(info.error);
          setResults([]);
          setLoading(false);
          return;
        }
        setQuery(info.normalized);
        if (info.type === "weighted") {
          setBarcodeWarning(_BARCODE_TYPE_LABELS.weighted);
          setWeightedInfo({
            itemCode: info.item_code,
            embeddedValue: info.embedded_value,
            fullCode: info.normalized,
          });
          setResults([]);
          setLoading(false);
          return;
        }
        if (info.type !== "product")
          setBarcodeWarning(_BARCODE_TYPE_LABELS[info.type]);
        url = `/api/search-off?barcode=${encodeURIComponent(info.normalized)}`;
      } else {
        const params = new URLSearchParams({ chain });
        if (q.trim()) params.set("q", q.trim());
        if (filterBrand) params.set("brand", filterBrand);
        if (filterCategory) params.set("category", filterCategory);
        url = `/api/search-off?${params}`;
      }
      setResults((await (await fetch(url)).json()).results || []);
    } catch (e) {
      setError(String(e));
    } finally {
      setLoading(false);
    }
  }

  async function pick(product) {
    setSaving(true);
    try {
      await fetch("/api/match", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          chain,
          item_name: itemName,
          barcode: product.barcode,
          raw_barcode: lastRawScan.current || product.barcode,
          receipt_id: receiptId || null,
        }),
      });
      onSaved();
    } catch (e) {
      setError(String(e));
      setSaving(false);
    }
  }

  return (
    <div className="space-y-3">
      {showScanner && (
        <BarcodeScanner
          onScan={handleScan}
          onClose={() => setShowScanner(false)}
        />
      )}
      {/* Search row */}
      <div className="flex gap-2">
        <button
          onClick={() => setShowScanner(true)}
          className="px-3 py-2 border border-gray-200 text-gray-600 text-xs font-semibold rounded-lg active:bg-gray-100 whitespace-nowrap"
        >
          📷 Scansiona
        </button>
        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && doSearch(query)}
          placeholder="Cerca per nome o codice a barre…"
          className="flex-1 min-w-0 px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#2d7a3a]/30 focus:border-[#2d7a3a]"
        />
        <button
          onClick={() => doSearch(query)}
          disabled={loading}
          className="px-3 py-2 bg-[#2d7a3a] text-white text-sm font-semibold rounded-lg disabled:opacity-60 active:bg-[#236130] whitespace-nowrap"
        >
          {loading ? "…" : "Cerca"}
        </button>
      </div>

      {!mongoOk && (
        <p className="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2">
          Database prodotti offline — scansiona o inserisci un codice a barre
          per cercare.
        </p>
      )}

      {/* Advanced filters */}
      <div>
        <button
          onClick={() => setShowAdvanced((v) => !v)}
          className="text-xs text-gray-400 hover:text-gray-600 flex items-center gap-1"
        >
          <span>{showAdvanced ? "▾" : "▸"}</span>
          <span>Filtri avanzati</span>
          {(filterBrand || filterCategory) && (
            <span className="ml-1 px-1.5 py-0.5 bg-[#2d7a3a]/10 text-[#2d7a3a] rounded-full text-[10px] font-semibold">
              {[filterBrand, filterCategory].filter(Boolean).length}
            </span>
          )}
        </button>
        {showAdvanced && (
          <div className="flex gap-2 mt-2">
            <AutocompleteInput
              placeholder="Marca (es. Twinings)"
              value={filterBrand}
              onChange={setFilterBrand}
              field="brand"
            />
            <AutocompleteInput
              placeholder="Categoria (es. Tè)"
              value={filterCategory}
              onChange={setFilterCategory}
              field="category"
            />
          </div>
        )}
      </div>

      {error && <p className="text-sm text-red-500">Errore: {error}</p>}
      {barcodeWarning && (
        <div className="flex items-start gap-2 p-2.5 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-800">
          <span className="flex-shrink-0 mt-0.5">&#9888;</span>
          <span>{barcodeWarning}</span>
        </div>
      )}
      {weightedInfo && (
        <div className="p-3 bg-white border border-amber-200 rounded-xl space-y-2">
          <div className="text-sm font-semibold text-gray-700">
            Articolo pesato/prezzato
          </div>
          <div className="flex items-center gap-3 text-xs text-gray-500">
            <span>
              Codice articolo:{" "}
              <span className="font-mono font-bold text-gray-700">
                {weightedInfo.itemCode}
              </span>
            </span>
            {weightedInfo.embeddedValue != null && (
              <span>
                Valore:{" "}
                <span className="font-mono font-bold text-gray-700">
                  {weightedInfo.embeddedValue}
                </span>
                <span className="text-gray-400 ml-1">
                  (centesimi prezzo o grammi)
                </span>
              </span>
            )}
          </div>
          <p className="text-xs text-gray-400">
            Questo è un codice in negozio per {chain || "questa catena"}. Verrà
            raggruppato con altri acquisti dello stesso articolo
            indipendentemente da peso/prezzo.
          </p>
          <button
            onClick={() => pick({ barcode: weightedInfo.itemCode })}
            disabled={saving}
            className="px-3 py-1.5 bg-[#2d7a3a] text-white text-xs font-bold rounded-lg disabled:opacity-60 active:bg-[#236130]"
          >
            {saving
              ? "…"
              : `Salva come articolo a peso ${weightedInfo.itemCode}`}
          </button>
        </div>
      )}
      {results && results.length === 0 && !loading && !weightedInfo && (
        <div className="flex items-center justify-between gap-3 py-1">
          <p className="text-sm text-gray-400">Nessun risultato.</p>
          {looksLikeBarcode(query) && (
            <button
              onClick={() => pick({ barcode: query.trim() })}
              disabled={saving}
              className="px-3 py-1.5 bg-gray-700 text-white text-xs font-semibold rounded-lg disabled:opacity-60 active:bg-gray-900 whitespace-nowrap"
            >
              {saving ? "…" : `Salva codice a barre ${query.trim()}`}
            </button>
          )}
        </div>
      )}

      {results &&
        results.map((p, i) => (
          <div
            key={i}
            className="flex items-start gap-3 p-3 bg-white border border-gray-100 rounded-xl"
          >
            <img
              src={p.barcode ? offImg(p.barcode) : PLACEHOLDER_IMG}
              alt={p.product_name}
              onError={(e) => {
                e.target.onerror = null;
                e.target.src = PLACEHOLDER_IMG;
              }}
              className="w-12 h-12 object-contain rounded-lg border border-gray-100 bg-gray-50 flex-shrink-0"
            />
            <div className="flex-1 min-w-0">
              <div className="text-sm font-semibold text-gray-800 truncate">
                {p.barcode ? (
                  <a
                    href={`https://world.openfoodfacts.org/product/${p.barcode}`}
                    target="_blank"
                    className="hover:text-[#2d7a3a]"
                  >
                    {p.product_name}
                  </a>
                ) : (
                  p.product_name
                )}
              </div>
              <div className="flex items-center gap-1.5 flex-wrap mt-0.5">
                {p.brands && (
                  <span className="text-xs text-gray-400">{p.brands}</span>
                )}
                {p.quantity && (
                  <span className="text-xs font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded-md">
                    {p.quantity}
                  </span>
                )}
              </div>
              <div className="text-xs text-gray-400 mt-0.5">
                {p.energy_kcal != null && `${Math.round(p.energy_kcal)} kcal`}
                {p.fat != null && ` · fat ${fmt(p.fat)}g`}
                {p.proteins != null && ` · prot ${fmt(p.proteins)}g`}
              </div>
            </div>
            <div className="flex flex-col items-end gap-1.5 flex-shrink-0">
              <div className="flex gap-1">
                <button
                  onClick={() => openDebug(p)}
                  className="px-2 py-1.5 border border-gray-200 text-gray-400 text-xs font-mono font-semibold rounded-lg active:bg-gray-100"
                >
                  {"{}"}
                </button>
                <button
                  onClick={() => pick(p)}
                  disabled={saving}
                  className="px-3 py-1.5 bg-[#2d7a3a] text-white text-xs font-bold rounded-lg disabled:opacity-60 active:bg-[#236130]"
                >
                  {saving ? "…" : "Usa questo"}
                </button>
              </div>
            </div>
          </div>
        ))}

      {debugProduct && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
          onClick={() => setDebugProduct(null)}
        >
          <div
            className="bg-white rounded-2xl shadow-xl w-full max-w-lg mx-4 max-h-[80vh] flex flex-col"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="flex items-center justify-between px-4 py-3 border-b border-gray-100">
              <span className="font-semibold text-sm text-gray-700 truncate">
                {debugProduct.product_name}
              </span>
              <button
                onClick={() => setDebugProduct(null)}
                className="text-gray-400 text-lg leading-none ml-2"
              >
                ✕
              </button>
            </div>
            {debugProduct._loading ? (
              <p className="p-4 text-sm text-gray-400">Caricamento…</p>
            ) : (
              <div className="overflow-auto p-4 text-xs font-mono">
                <JsonNode value={debugProduct} depth={0} />
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
