import { useEffect, useState } from "react";
import type { Item, Product } from "../types.js";
import { Icon, Field, inputStyle } from "./primitives/index.js";

export type ScanResult =
  | { kind: "item"; item: Item }
  | { kind: "product"; product: Product };

// Scan-friendly picker. Auto-focuses on mount so a barcode scanner
// can fire immediately. Exact (case-insensitive) match against assetId
// (per-instance) or sku (per-product) → calls onMatch and clears itself.
// Asset id wins ties since it's the more specific identifier.
export function ScanField({
  items,
  products,
  onMatch,
  onScanNoMatch,
  matchedLabel,
  mode = "both",
}: {
  items: Item[];
  products?: Product[];
  onMatch: (result: ScanResult) => void;
  // Fired once after a debounce when the scanned text doesn't resolve to
  // any known asset id or SKU. The parent can use the raw value (e.g. to
  // open a "create new product" form prefilled with the scanned SKU).
  onScanNoMatch?: (raw: string) => void;
  matchedLabel: string | null;
  mode?: "both" | "assetId" | "sku";
}) {
  const [scan, setScan] = useState("");
  const [feedback, setFeedback] = useState<{ type: "matched" | "miss"; text: string } | null>(null);

  useEffect(() => {
    const trimmed = scan.trim().toLowerCase();
    if (!trimmed) {
      setFeedback(null);
      return;
    }
    const hit = lookup(trimmed, items, products, mode);
    if (hit) {
      const label = hit.kind === "item" ? hit.item.name : hit.product.sku;
      onMatch(hit);
      setScan("");
      setFeedback({ type: "matched", text: `Matched ${label}` });
    }
  }, [scan]); // eslint-disable-line react-hooks/exhaustive-deps

  // Show "no match" only after the user has stopped typing for a beat —
  // avoids flashing "no match" mid-type while a multi-char SKU is entered.
  useEffect(() => {
    if (!scan.trim() || feedback?.type === "matched") return;
    const timer = setTimeout(() => {
      const raw = scan.trim();
      if (!lookup(raw.toLowerCase(), items, products, mode)) {
        if (onScanNoMatch) {
          onScanNoMatch(raw);
          setScan("");
          setFeedback(null);
        } else {
          const missText = mode === "assetId" ? "No item matches that asset ID."
            : mode === "sku" ? "No product matches that SKU."
            : "No asset id or SKU matches that.";
          setFeedback({ type: "miss", text: missText });
        }
      }
    }, 400);
    return () => clearTimeout(timer);
  }, [scan, items, products]); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <Field label={mode === "assetId" ? "Scan asset ID" : mode === "sku" ? "Scan SKU" : "Scan asset id or SKU"}>
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: 8,
          ...inputStyle,
          padding: "0 12px",
        }}
      >
        <Icon name="search" size={14} color="var(--ink-3)" />
        <input
          autoFocus
          value={scan}
          onChange={(e) => setScan(e.target.value)}
          onFocus={(e) => e.currentTarget.select()}
          placeholder={mode === "assetId" ? "123456" : mode === "sku" ? "SKU-XXXXXX" : "123456 or SKU-XXXXXX"}
          style={{
            border: "none",
            outline: "none",
            background: "transparent",
            padding: "10px 0",
            fontSize: 13,
            flex: 1,
            color: "var(--ink)",
            fontFamily: "var(--mono)",
          }}
        />
        {matchedLabel && !scan && (
          <span
            className="mono"
            style={{
              fontSize: 11,
              color: "var(--sage)",
              whiteSpace: "nowrap",
            }}
          >
            ✓ {matchedLabel}
          </span>
        )}
      </div>
      {feedback && (
        <span
          style={{
            fontSize: 11,
            color: feedback.type === "matched" ? "var(--sage)" : "var(--terracotta)",
            marginTop: 2,
          }}
        >
          {feedback.text}
        </span>
      )}
    </Field>
  );
}

export function lookup(
  trimmed: string,
  items: Item[],
  products?: Product[],
  mode: "both" | "assetId" | "sku" = "both",
): ScanResult | null {
  if (mode !== "sku") {
    const itemHit = items.find((i) => i.assetId.toLowerCase() === trimmed);
    if (itemHit) return { kind: "item", item: itemHit };
  }
  if (mode !== "assetId") {
    const skuHitItem = items.find((i) => i.sku.toLowerCase() === trimmed);
    if (skuHitItem) return { kind: "item", item: skuHitItem };
    if (products) {
      const productHit = products.find((p) => p.sku.toLowerCase() === trimmed);
      if (productHit) return { kind: "product", product: productHit };
    }
  }
  return null;
}
