import { useEffect, useMemo, useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { Bootstrap, InventoryItem, Item, Product, Strain } from "../../types.js";
import {
  ASSET_ID_RE,
  TYPES,
  TODAY_STR,
  enrichItems,
  getLastInstance,
} from "../../types.js";
import { fmt } from "../../format.js";
import { api } from "../../api.js";
import { Btn, Field, Input, Select } from "../primitives/index.js";
import { ScanField, type ScanResult } from "../ScanField.js";
import { ModalBackdrop, ModalHeader, ModalFooter } from "./ModalChrome.js";

const NEW_BRAND = "__new_brand__";
const NEW_SHOP = "__new_shop__";
const NEW_BIN = "__new_bin__";

type Step = "select" | "details" | "done";

export function AddInventoryFlow({ data, onClose }: { data: Bootstrap; onClose: () => void }) {
  const qc = useQueryClient();

  const items = useMemo(() => enrichItems(data), [data]);
  const [step, setStep] = useState<Step>("select");
  const [productId, setProductId] = useState<string | null>(null);
  const [savedAssetId, setSavedAssetId] = useState<string | null>(null);

  const product = productId
    ? data.products.find((p) => p.id === productId) ?? null
    : null;
  const productName =
    product?.strainId
      ? data.strains.find((s) => s.id === product.strainId)?.name ?? ""
      : "";

  const goToDetails = (id: string) => {
    setProductId(id);
    setStep("details");
  };

  return (
    <ModalBackdrop onClose={onClose}>
      <div
        style={{
          width: "min(840px, 96vw)",
          margin: "40px 20px",
          background: "var(--bg)",
          border: "1px solid var(--line)",
          borderRadius: "var(--r-lg)",
          boxShadow: "var(--shadow-lg)",
        }}
      >
        <ModalHeader
          title={
            step === "select"
              ? "Add inventory"
              : step === "details"
                ? `Add ${productName}`
                : "Saved"
          }
          eyebrow={
            step === "select"
              ? "Step 1 · Scan or pick a product"
              : step === "details"
                ? "Step 2 · This batch's details"
                : "Inventory item created"
          }
          onClose={onClose}
        />

        {step === "select" && (
          <SelectProductStep
            data={data}
            items={items}
            onPickProduct={(id) => goToDetails(id)}
            onClose={onClose}
          />
        )}

        {step === "details" && product && (
          <InstanceDetailsStep
            data={data}
            items={items}
            product={product}
            productName={productName}
            onBack={() => setStep("select")}
            onSaved={(assetId) => {
              setSavedAssetId(assetId);
              qc.invalidateQueries({ queryKey: ["bootstrap"] });
              setStep("done");
            }}
          />
        )}

        {step === "done" && savedAssetId && product && (
          <DonePane
            assetId={savedAssetId}
            productName={productName}
            onAddAnother={() => {
              setSavedAssetId(null);
              setProductId(null);
              setStep("select");
            }}
            onClose={onClose}
          />
        )}
      </div>
    </ModalBackdrop>
  );
}

// ─── Step 1 ─────────────────────────────────────────────────────────

function SelectProductStep({
  data,
  items,
  onPickProduct,
  onClose,
}: {
  data: Bootstrap;
  items: Item[];
  onPickProduct: (productId: string) => void;
  onClose: () => void;
}) {
  const qc = useQueryClient();

  const [creating, setCreating] = useState(false);
  const [pickedProductId, setPickedProductId] = useState<string>(
    data.products[0]?.id ?? "",
  );

  // New-product subform
  const [newSku, setNewSku] = useState("");
  const [newName, setNewName] = useState(""); // strain name; doubles as display name
  const [newType, setNewType] = useState("Flower");
  const [newBrandId, setNewBrandId] = useState<string>(
    data.brands[0]?.id ?? NEW_BRAND,
  );
  const [newBrandName, setNewBrandName] = useState("");
  const [error, setError] = useState<string | null>(null);

  const handleScan = (result: ScanResult) => {
    if (result.kind === "product") {
      onPickProduct(result.product.id);
    } else {
      // Asset scan in add-inventory flow — interpret as "I want another of
      // this kind", select that product so the form pre-fills from the
      // existing instance.
      onPickProduct(result.item.productId);
    }
  };

  const handleNoMatch = (raw: string) => {
    // Scanned a SKU we've never seen — open the create form prefilled.
    setNewSku(raw.toUpperCase());
    setCreating(true);
  };

  const matchedStrain: Strain | null = useMemo(() => {
    const q = newName.trim().toLowerCase();
    if (!q) return null;
    return data.strains.find((s) => s.name.trim().toLowerCase() === q) ?? null;
  }, [newName, data.strains]);

  const create = useMutation({
    mutationFn: async () => {
      const sku = newSku.trim();
      const name = newName.trim();
      if (!sku) throw new Error("SKU required");
      if (!name) throw new Error("Name (strain) required");
      const cfg = TYPES.find((t) => t.id === newType);
      if (!cfg) throw new Error("Type required");

      let brandId: string | null = null;
      if (newBrandId === NEW_BRAND) {
        if (!newBrandName.trim()) throw new Error("New brand name required");
        const b = await api.createBrand(newBrandName.trim());
        brandId = b.id;
      } else {
        brandId = newBrandId || null;
      }

      const result = await api.createProduct({
        sku,
        type: newType,
        kind: cfg.kind,
        strainId: matchedStrain?.id,
        strainName: matchedStrain ? undefined : name,
        brandId,
      });
      return result.id;
    },
    onSuccess: async (id) => {
      await qc.invalidateQueries({ queryKey: ["bootstrap"] });
      onPickProduct(id);
    },
    onError: (e: Error) => setError(e.message),
  });

  const isNewBrand = newBrandId === NEW_BRAND;

  return (
    <>
      <div style={{ padding: 32 }}>
        <ScanField
          items={items}
          products={data.products}
          onMatch={handleScan}
          onScanNoMatch={creating ? undefined : handleNoMatch}
          matchedLabel={null}
        />

        {data.products.length > 0 && !creating && (
          <div style={{ marginTop: 16 }}>
            <Field label="Or pick an existing product">
              <Select
                value={pickedProductId}
                onChange={(e) => setPickedProductId(e.target.value)}
              >
                {data.products.map((p) => {
                  const strainName =
                    data.strains.find((s) => s.id === p.strainId)?.name ?? "?";
                  return (
                    <option key={p.id} value={p.id}>
                      {strainName} · {p.sku} ({p.type})
                    </option>
                  );
                })}
              </Select>
            </Field>
          </div>
        )}

        {!creating && (
          <div style={{ marginTop: 18 }}>
            <Btn variant="ghost" icon="plus" onClick={() => setCreating(true)}>
              Create a new product
            </Btn>
          </div>
        )}

        {creating && (
          <div
            style={{
              marginTop: 24,
              padding: 20,
              background: "var(--bg-2)",
              border: "1px solid var(--line)",
              borderRadius: "var(--r-md)",
            }}
          >
            <div className="smallcaps" style={{ color: "var(--ink-3)", marginBottom: 12 }}>
              New product (catalog entry)
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 16 }}>
              <Field label="SKU" hint="The barcode you'll scan">
                <Input
                  value={newSku}
                  placeholder="SKU-XXXXXX"
                  onChange={(e) => setNewSku(e.target.value)}
                  autoFocus={!newSku}
                />
              </Field>
              <Field label="Type">
                <Select value={newType} onChange={(e) => setNewType(e.target.value)}>
                  {TYPES.map((t) => (
                    <option key={t.id} value={t.id}>
                      {t.id} ({t.kind})
                    </option>
                  ))}
                </Select>
              </Field>
              <Field
                label="Name (strain)"
                span={2}
                hint={
                  matchedStrain
                    ? `Will link to existing strain "${matchedStrain.name}".`
                    : "Will create a new strain entry from this name."
                }
              >
                <Input
                  value={newName}
                  placeholder="e.g. Garden Ghost"
                  onChange={(e) => setNewName(e.target.value)}
                />
              </Field>
              <Field label="Brand">
                <Select
                  value={newBrandId}
                  onChange={(e) => setNewBrandId(e.target.value)}
                >
                  {data.brands.map((b) => (
                    <option key={b.id} value={b.id}>
                      {b.name}
                    </option>
                  ))}
                  <option value={NEW_BRAND}>+ Add new brand…</option>
                </Select>
              </Field>
              {isNewBrand && (
                <Field label="New brand name">
                  <Input
                    value={newBrandName}
                    onChange={(e) => setNewBrandName(e.target.value)}
                    placeholder="e.g. Foxglove Farms"
                  />
                </Field>
              )}
            </div>
            {error && (
              <div style={{ marginTop: 12, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
            )}
          </div>
        )}
      </div>

      <ModalFooter>
        <div style={{ fontSize: 12, color: "var(--ink-3)" }}>
          {creating
            ? "Create the product, then we'll capture this batch's details."
            : "Scan a SKU, pick a product, or create one."}
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <Btn variant="ghost" onClick={onClose}>
            Cancel
          </Btn>
          {creating ? (
            <>
              <Btn variant="ghost" onClick={() => setCreating(false)}>
                Back
              </Btn>
              <Btn
                variant="primary"
                icon="check"
                disabled={create.isPending}
                onClick={() => create.mutate()}
              >
                {create.isPending ? "Creating…" : "Create product"}
              </Btn>
            </>
          ) : (
            data.products.length > 0 && (
              <Btn
                variant="primary"
                icon="plus"
                disabled={!pickedProductId}
                onClick={() => onPickProduct(pickedProductId)}
              >
                Add inventory
              </Btn>
            )
          )}
        </div>
      </ModalFooter>
    </>
  );
}

// ─── Step 2 ─────────────────────────────────────────────────────────

function InstanceDetailsStep({
  data,
  items,
  product,
  productName,
  onBack,
  onSaved,
}: {
  data: Bootstrap;
  items: Item[];
  product: Product;
  productName: string;
  onBack: () => void;
  onSaved: (assetId: string) => void;
}) {
  const last: InventoryItem | null = useMemo(
    () => getLastInstance(data.inventoryItems, product.id),
    [data.inventoryItems, product.id],
  );

  const cfg = TYPES.find((t) => t.id === product.type);
  const isDiscrete = product.kind === "discrete";

  // form.price is total for bulk, per-unit for discrete (matches existing UI).
  const initialPrice = (() => {
    if (!last) return isDiscrete ? 5 : 45;
    if (isDiscrete && last.countOriginal > 0) return last.price / last.countOriginal;
    return last.price;
  })();

  const [assetId, setAssetId] = useState("");
  const [form, setForm] = useState({
    shopId: last?.shopId ?? data.shops[0]?.id ?? NEW_SHOP,
    binId: data.bins[0]?.id ?? NEW_BIN,
    weight: last?.weight ?? (isDiscrete ? 0 : 3.5),
    countOriginal: last?.countOriginal ?? (isDiscrete ? 1 : 0),
    unitWeight: last?.unitWeight ?? (isDiscrete ? 0.7 : 0),
    price: initialPrice,
    thc: last?.thc ?? 22,
    cbd: last?.cbd ?? 0.4,
    totalCannabinoids: last?.totalCannabinoids ?? 26,
    purchaseDate: TODAY_STR,
  });
  const [newShopName, setNewShopName] = useState("");
  const [newShopLocation, setNewShopLocation] = useState("");
  const [newBinName, setNewBinName] = useState("");
  const [newBinCapacity, setNewBinCapacity] = useState(10);
  const [error, setError] = useState<string | null>(null);

  const update = <K extends keyof typeof form>(k: K, v: (typeof form)[K]) =>
    setForm((f) => ({ ...f, [k]: v }));

  const totalPrice = isDiscrete ? form.price * form.countOriginal : form.price;
  const cpg = !isDiscrete && form.weight > 0 ? form.price / form.weight : 0;
  const assetIdValid = ASSET_ID_RE.test(assetId);
  const assetIdConflict =
    assetIdValid && data.inventoryItems.some((i) => i.assetId === assetId);

  const save = useMutation({
    mutationFn: async () => {
      if (!assetIdValid) throw new Error("Asset id must be exactly 6 digits");
      if (assetIdConflict) throw new Error("Asset id already used");
      let { shopId, binId } = form;
      if (shopId === NEW_SHOP) {
        if (!newShopName.trim()) throw new Error("New shop name required");
        const s = await api.createShop({
          name: newShopName.trim(),
          location: newShopLocation.trim(),
        });
        shopId = s.id;
      }
      if (binId === NEW_BIN) {
        if (!newBinName.trim()) throw new Error("New bin name required");
        const b = await api.createBin({
          name: newBinName.trim(),
          capacity: newBinCapacity,
        });
        binId = b.id;
      }
      return api.createInventoryItem({
        assetId,
        productId: product.id,
        shopId,
        binId,
        weight: isDiscrete ? undefined : form.weight,
        countOriginal: isDiscrete ? form.countOriginal : undefined,
        unitWeight: isDiscrete ? form.unitWeight : undefined,
        price: totalPrice,
        thc: form.thc,
        cbd: form.cbd,
        totalCannabinoids: form.totalCannabinoids,
        purchaseDate: form.purchaseDate,
      });
    },
    onSuccess: (result) => onSaved(result.assetId),
    onError: (e: Error) => setError(e.message),
  });

  const isNewShop = form.shopId === NEW_SHOP;
  const isNewBin = form.binId === NEW_BIN;

  const priorCount = items.filter((i) => i.productId === product.id).length;
  const brandName = data.brands.find((b) => b.id === product.brandId)?.name ?? "—";

  return (
    <>
      <div style={{ padding: 32 }}>
        <div
          style={{
            marginBottom: 20,
            padding: "12px 16px",
            background: "var(--bg-2)",
            border: "1px solid var(--line)",
            borderRadius: "var(--r-sm)",
            fontSize: 12,
            color: "var(--ink-3)",
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
          }}
        >
          <span>
            <strong style={{ color: "var(--ink-2)" }}>{productName}</strong> · {brandName} · {product.type} ·{" "}
            <span className="mono">{product.sku}</span>
          </span>
          <span>
            {priorCount > 0
              ? `${priorCount} prior instance${priorCount === 1 ? "" : "s"} — fields autofilled.`
              : "First instance of this product."}
          </span>
        </div>

        <div className="smallcaps" style={{ color: "var(--ink-3)", marginBottom: 16 }}>
          Asset tag
        </div>
        <Field
          label="Asset id (6 digits)"
          hint={
            assetIdConflict
              ? "That asset id is already in use."
              : "From the next sticker on your roll. Required."
          }
        >
          <Input
            autoFocus
            value={assetId}
            inputMode="numeric"
            maxLength={6}
            placeholder="000000"
            onChange={(e) => setAssetId(e.target.value.replace(/\D/g, "").slice(0, 6))}
            style={{
              fontFamily: "var(--mono)",
              letterSpacing: "0.1em",
              borderColor: assetIdConflict ? "var(--terracotta)" : undefined,
            }}
          />
        </Field>

        <div
          className="smallcaps"
          style={{ color: "var(--ink-3)", margin: "28px 0 16px" }}
        >
          Source
        </div>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(2, 1fr)",
            gap: 16,
            marginBottom: 28,
          }}
        >
          <Field label="Shop">
            <Select value={form.shopId} onChange={(e) => update("shopId", e.target.value)}>
              {data.shops.map((s) => (
                <option key={s.id} value={s.id}>
                  {s.name}
                </option>
              ))}
              <option value={NEW_SHOP}>+ Add new shop…</option>
            </Select>
          </Field>
          <Field label="Bin">
            <Select value={form.binId} onChange={(e) => update("binId", e.target.value)}>
              {data.bins.map((b) => (
                <option key={b.id} value={b.id}>
                  {b.name}
                </option>
              ))}
              <option value={NEW_BIN}>+ Add new bin…</option>
            </Select>
          </Field>
          {isNewShop && (
            <>
              <Field label="New shop name">
                <Input
                  value={newShopName}
                  onChange={(e) => setNewShopName(e.target.value)}
                  placeholder="e.g. Greenleaf Co-op"
                />
              </Field>
              <Field label="Location (optional)">
                <Input
                  value={newShopLocation}
                  onChange={(e) => setNewShopLocation(e.target.value)}
                  placeholder="e.g. Capitol Hill"
                />
              </Field>
            </>
          )}
          {isNewBin && (
            <>
              <Field label="New bin name">
                <Input
                  value={newBinName}
                  onChange={(e) => setNewBinName(e.target.value)}
                  placeholder="e.g. A1"
                />
              </Field>
              <Field label="Capacity">
                <Input
                  type="number"
                  min={1}
                  step={1}
                  value={newBinCapacity}
                  onChange={(e) =>
                    setNewBinCapacity(Math.max(1, Math.floor(+e.target.value || 1)))
                  }
                />
              </Field>
            </>
          )}
        </div>

        <div className="smallcaps" style={{ color: "var(--ink-3)", marginBottom: 16 }}>
          Acquisition
        </div>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(4, 1fr)",
            gap: 16,
            marginBottom: 8,
          }}
        >
          {isDiscrete ? (
            <>
              <Field label={`Quantity (${cfg!.unit})`}>
                <Input
                  type="number"
                  step="1"
                  value={form.countOriginal}
                  onChange={(e) => update("countOriginal", +e.target.value)}
                />
              </Field>
              <Field label="Per-unit weight (g)" hint="For grams stats">
                <Input
                  type="number"
                  step="0.1"
                  value={form.unitWeight}
                  onChange={(e) => update("unitWeight", +e.target.value)}
                />
              </Field>
            </>
          ) : (
            <Field label={`Size (${cfg?.unit ?? "g"})`} span={2}>
              <Input
                type="number"
                step="0.1"
                value={form.weight}
                onChange={(e) => update("weight", +e.target.value)}
              />
            </Field>
          )}
          <Field label={isDiscrete ? "Price per unit ($)" : "Price ($)"}>
            <Input
              type="number"
              step="0.01"
              value={form.price}
              onChange={(e) => update("price", +e.target.value)}
            />
          </Field>
          <Field label="Purchase date">
            <Input
              type="date"
              value={form.purchaseDate}
              onChange={(e) => update("purchaseDate", e.target.value)}
            />
          </Field>
        </div>

        {!isDiscrete && cpg > 0 && (
          <div style={{ marginTop: 12, fontSize: 12, color: "var(--ink-3)" }}>
            Cost per {cfg?.unit ?? "g"}:{" "}
            <span className="mono" style={{ color: "var(--ink-2)" }}>
              {fmt.money(cpg)}
            </span>
          </div>
        )}
        {isDiscrete && form.price > 0 && form.countOriginal > 0 && (
          <div style={{ marginTop: 12, fontSize: 12, color: "var(--ink-3)" }}>
            Total:{" "}
            <span className="mono" style={{ color: "var(--ink-2)" }}>
              {fmt.money(totalPrice)}
            </span>
            <span style={{ marginLeft: 6 }}>
              ({form.countOriginal} × {fmt.money(form.price)})
            </span>
          </div>
        )}

        <div
          className="smallcaps"
          style={{ color: "var(--ink-3)", margin: "28px 0 16px" }}
        >
          Cannabinoid profile
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 16 }}>
          <Field label="THC %">
            <Input
              type="number"
              step="0.1"
              value={form.thc}
              onChange={(e) => update("thc", +e.target.value)}
            />
          </Field>
          <Field label="CBD %">
            <Input
              type="number"
              step="0.1"
              value={form.cbd}
              onChange={(e) => update("cbd", +e.target.value)}
            />
          </Field>
          <Field label="Total cannabinoids %">
            <Input
              type="number"
              step="0.1"
              value={form.totalCannabinoids}
              onChange={(e) => update("totalCannabinoids", +e.target.value)}
            />
          </Field>
        </div>

        {error && (
          <div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
        )}
      </div>

      <ModalFooter>
        <Btn variant="ghost" onClick={onBack}>
          ← Back
        </Btn>
        <Btn
          variant="primary"
          icon="check"
          disabled={save.isPending || !assetIdValid || assetIdConflict}
          onClick={() => save.mutate()}
        >
          {save.isPending ? "Saving…" : "Save inventory item"}
        </Btn>
      </ModalFooter>
    </>
  );
}

// ─── Step 3 ─────────────────────────────────────────────────────────

function DonePane({
  assetId,
  productName,
  onAddAnother,
  onClose,
}: {
  assetId: string;
  productName: string;
  onAddAnother: () => void;
  onClose: () => void;
}) {
  return (
    <>
      <div style={{ padding: "48px 32px 32px", textAlign: "center" }}>
        <div className="smallcaps" style={{ color: "var(--ink-3)" }}>Asset id</div>
        <div
          className="mono"
          style={{
            fontSize: 64,
            fontWeight: 600,
            letterSpacing: "0.08em",
            margin: "16px 0",
            color: "var(--ink)",
          }}
        >
          {assetId}
        </div>
        <div style={{ fontSize: 13, color: "var(--ink-2)", marginBottom: 8 }}>
          Stick label{" "}
          <span className="mono" style={{ color: "var(--ink)" }}>{assetId}</span>{" "}
          on the {productName}.
        </div>
      </div>
      <ModalFooter>
        <Btn variant="ghost" onClick={onAddAnother}>
          + Add another
        </Btn>
        <Btn variant="primary" icon="check" onClick={onClose}>
          Done
        </Btn>
      </ModalFooter>
    </>
  );
}
