import { useEffect, useMemo, useState } from "react";
import type { Bootstrap, Item } from "../types.js";
import { TYPES, helpers, TODAY_STR, enrichItems } from "../types.js";
import { remainingShort } from "../stats.js";
import { fmt, TYPE_GLYPHS } from "../format.js";
import { Btn, Card, Pill, Icon, Select, inputStyle } from "../components/primitives/index.js";

type FilterKey = "active" | "checked-out" | "consumed" | "gone" | "all";
type SortKey = "recent" | "name" | "thc" | "remaining" | "price" | "audit";
type ViewKey = "flat" | "grouped";

const GRID_COLS = "32px 2fr 1fr 1fr 0.6fr 0.6fr 0.9fr 0.9fr 0.8fr";

export function Inventory({
  data,
  onSelectItem,
  onAddInventory,
  onAuditNew,
}: {
  data: Bootstrap;
  onSelectItem: (i: Item) => void;
  onAddInventory: () => void;
  onAuditNew: () => void;
}) {
  const items = useMemo(() => enrichItems(data), [data]);

  const [filter, setFilter] = useState<FilterKey>("active");
  const [typeFilter, setTypeFilter] = useState<string>("all");
  const [sortBy, setSortBy] = useState<SortKey>("recent");
  const [search, setSearch] = useState("");
  const [view, setView] = useState<ViewKey>(
    () => (localStorage.getItem("apothecary.inventoryView") as ViewKey | null) ?? "flat",
  );
  useEffect(() => {
    localStorage.setItem("apothecary.inventoryView", view);
  }, [view]);

  const sortFn = (a: Item, b: Item) => {
    if (sortBy === "recent") return +new Date(b.purchaseDate) - +new Date(a.purchaseDate);
    if (sortBy === "name") return a.name.localeCompare(b.name);
    if (sortBy === "thc") return b.thc - a.thc;
    if (sortBy === "remaining")
      return helpers.estimatedRemaining(b, TODAY_STR) - helpers.estimatedRemaining(a, TODAY_STR);
    if (sortBy === "price") return b.price - a.price;
    if (sortBy === "audit")
      return helpers.daysSinceCheck(b, TODAY_STR) - helpers.daysSinceCheck(a, TODAY_STR);
    return 0;
  };

  const filtered = useMemo(() => {
    let out = items;
    if (filter === "active") out = out.filter((i) => i.status === "active");
    else if (filter === "checked-out") out = out.filter((i) => i.status === "checked-out");
    else if (filter === "consumed") out = out.filter((i) => i.status === "consumed");
    else if (filter === "gone") out = out.filter((i) => i.status === "gone");
    if (typeFilter !== "all") out = out.filter((i) => i.type === typeFilter);
    if (search) {
      const q = search.toLowerCase();
      out = out.filter((i) => {
        const brand = helpers.brandName(data, i.brandId).toLowerCase();
        const shop = helpers.shopName(data, i.shopId).toLowerCase();
        return (
          i.name.toLowerCase().includes(q) ||
          brand.includes(q) ||
          shop.includes(q) ||
          i.sku.toLowerCase().includes(q) ||
          i.assetId.toLowerCase().includes(q)
        );
      });
    }
    return out;
  }, [items, data, filter, typeFilter, search]);

  const sorted = useMemo(() => [...filtered].sort(sortFn), [filtered, sortBy]);

  // Grouped mode: bucket by productId. Same-product instances collapse under
  // a header that shows total count + total remaining + last purchase.
  type Group = {
    productId: string;
    label: string;
    sku: string;
    type: string;
    items: Item[];
  };
  const groups: Group[] = useMemo(() => {
    const byProduct = new Map<string, Item[]>();
    for (const i of filtered) {
      const arr = byProduct.get(i.productId) ?? [];
      arr.push(i);
      byProduct.set(i.productId, arr);
    }
    const out: Group[] = [];
    for (const [productId, list] of byProduct.entries()) {
      const first = list[0]!;
      out.push({
        productId,
        label: first.name,
        sku: first.sku,
        type: first.type,
        items: [...list].sort(sortFn),
      });
    }
    out.sort((a, b) => {
      const aMax = Math.max(...a.items.map((p) => +new Date(p.purchaseDate)));
      const bMax = Math.max(...b.items.map((p) => +new Date(p.purchaseDate)));
      return bMax - aMax;
    });
    return out;
  }, [filtered, sortBy]);

  return (
    <div
      style={{
        padding: "clamp(32px, 3vw, 64px) clamp(40px, 3vw, 80px) 80px",
        maxWidth: 2400,
        margin: "0 auto",
      }}
    >
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 24 }}>
        <div>
          <div className="smallcaps" style={{ color: "var(--ink-3)" }}>
            {sorted.length} item{sorted.length === 1 ? "" : "s"}
          </div>
          <h1
            className="serif"
            style={{ fontSize: 44, margin: "6px 0 0", fontWeight: 500, letterSpacing: "-0.02em" }}
          >
            Inventory
          </h1>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <Btn variant="secondary" icon="check" onClick={onAuditNew}>Audit</Btn>
          <Btn variant="primary" icon="plus" onClick={onAddInventory}>Add inventory</Btn>
        </div>
      </div>

      <Card style={{ marginBottom: 14, padding: 14 }}>
        <div style={{ display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" }}>
          <Segmented<FilterKey>
            value={filter}
            options={[
              ["active", "Active"],
              ["checked-out", "Checked out"],
              ["consumed", "Consumed"],
              ["gone", "Gone"],
              ["all", "All"],
            ]}
            onChange={setFilter}
          />

          <Segmented<ViewKey>
            value={view}
            options={[
              ["flat", "Flat"],
              ["grouped", "By product"],
            ]}
            onChange={setView}
          />

          <div
            style={{
              flex: 1,
              minWidth: 220,
              display: "flex",
              alignItems: "center",
              gap: 8,
              background: "var(--bg-2)",
              border: "1px solid var(--line)",
              borderRadius: "var(--r-md)",
              padding: "0 10px",
            }}
          >
            <Icon name="search" size={14} color="var(--ink-3)" />
            <input
              placeholder="Search by name, brand, shop, SKU, asset id…"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              style={{
                border: "none",
                outline: "none",
                background: "transparent",
                padding: "8px 0",
                fontSize: 13,
                flex: 1,
                color: "var(--ink)",
              }}
            />
            {search && (
              <button
                onClick={() => setSearch("")}
                style={{
                  background: "transparent",
                  border: "none",
                  cursor: "pointer",
                  padding: 2,
                  display: "inline-flex",
                  color: "var(--ink-3)",
                }}
              >
                <Icon name="close" size={12} />
              </button>
            )}
          </div>

          <Select
            value={typeFilter}
            onChange={(e) => setTypeFilter(e.target.value)}
            style={{ ...inputStyle, width: "auto", padding: "8px 10px" }}
          >
            <option value="all">All types</option>
            {TYPES.map((t) => (
              <option key={t.id} value={t.id}>{t.id}</option>
            ))}
          </Select>

          <Select
            value={sortBy}
            onChange={(e) => setSortBy(e.target.value as SortKey)}
            style={{ ...inputStyle, width: "auto", padding: "8px 10px" }}
          >
            <option value="recent">Recent first</option>
            <option value="name">Name (A–Z)</option>
            <option value="thc">THC % (high)</option>
            <option value="remaining">Remaining (high)</option>
            <option value="price">Price (high)</option>
            <option value="audit">Audit overdue first</option>
          </Select>
        </div>
      </Card>

      <Card padded={false}>
        <HeaderRow sortBy={sortBy} onSort={setSortBy} />
        {sorted.length === 0 && (
          <div style={{ padding: 60, textAlign: "center", color: "var(--ink-3)" }}>
            No items match these filters.
          </div>
        )}
        {view === "flat" &&
          sorted.map((i) => (
            <ItemRow key={i.id} i={i} data={data} onSelect={onSelectItem} />
          ))}
        {view === "grouped" &&
          groups.map((g) => (
            <div key={g.productId}>
              <GroupHeader group={g} />
              {g.items.map((i) => (
                <ItemRow key={i.id} i={i} data={data} onSelect={onSelectItem} indented />
              ))}
            </div>
          ))}
      </Card>
    </div>
  );
}

function Segmented<T extends string>({
  value,
  options,
  onChange,
}: {
  value: T;
  options: [T, string][];
  onChange: (v: T) => void;
}) {
  return (
    <div
      style={{
        display: "inline-flex",
        background: "var(--bg-2)",
        border: "1px solid var(--line)",
        borderRadius: "var(--r-md)",
        padding: 3,
      }}
    >
      {options.map(([k, l]) => (
        <button
          key={k}
          onClick={() => onChange(k)}
          style={{
            padding: "6px 14px",
            fontSize: 12,
            fontWeight: 500,
            borderRadius: 6,
            border: "none",
            background: value === k ? "var(--surface)" : "transparent",
            color: value === k ? "var(--ink)" : "var(--ink-3)",
            boxShadow: value === k ? "var(--shadow-sm)" : "none",
            cursor: "pointer",
          }}
        >
          {l}
        </button>
      ))}
    </div>
  );
}

const COL_SORT: (SortKey | null)[] = [null, "name", null, null, "thc", "price", "remaining", "audit", null];
const COL_LABELS = ["", "Item", "Brand", "Shop", "THC %", "Price", "Remaining", "Last checked", "Bin"];

function HeaderRow({ sortBy, onSort }: { sortBy: SortKey; onSort: (k: SortKey) => void }) {
  return (
    <div
      className="inv-header"
      style={{
        display: "grid",
        gridTemplateColumns: GRID_COLS,
        columnGap: 16,
        padding: "12px 20px",
        borderBottom: "1px solid var(--line)",
        background: "var(--bg-2)",
        fontSize: 11,
        color: "var(--ink-3)",
        textTransform: "uppercase",
        letterSpacing: "0.08em",
      }}
    >
      {COL_LABELS.map((label, i) => {
        const sk = COL_SORT[i];
        if (!sk) return <div key={i}>{label}</div>;
        const active = sortBy === sk;
        return (
          <button
            key={i}
            onClick={() => onSort(sk)}
            style={{
              background: "none",
              border: "none",
              padding: 0,
              cursor: "pointer",
              fontSize: "inherit",
              textTransform: "inherit",
              letterSpacing: "inherit",
              fontWeight: active ? 600 : "inherit",
              color: active ? "var(--ink)" : "var(--ink-3)",
              display: "flex",
              alignItems: "center",
              gap: 4,
            }}
          >
            {label}
            {active && <span style={{ fontSize: 9 }}>▼</span>}
          </button>
        );
      })}
    </div>
  );
}

function GroupHeader({
  group,
}: {
  group: {
    productId: string;
    label: string;
    sku: string;
    type: string;
    items: Item[];
  };
}) {
  // Aggregate remaining: bulk uses estimatedRemaining; discrete uses unitWeight × count.
  // Counts use status === "active" only — archived rows shouldn't inflate "on hand."
  const active = group.items.filter((i) => i.status === "active");
  const totalRemaining = active.reduce((s, i) => {
    if (i.kind === "bulk") return s + helpers.estimatedRemaining(i, TODAY_STR);
    const cur = i.countLastAudit ?? i.countOriginal;
    return s + cur * (i.unitWeight || 0);
  }, 0);
  const lastBuy = group.items.reduce((max, i) => {
    const t = +new Date(i.purchaseDate);
    return t > max ? t : max;
  }, 0);
  const cfg = TYPES.find((t) => t.id === group.type);

  return (
    <div
      style={{
        display: "flex",
        alignItems: "baseline",
        justifyContent: "space-between",
        gap: 16,
        padding: "16px 20px 10px",
        borderBottom: "1px solid var(--line)",
        background: "var(--bg-2)",
      }}
    >
      <div style={{ display: "flex", alignItems: "baseline", gap: 12, minWidth: 0 }}>
        <div style={{ fontFamily: "var(--serif)", fontSize: 18, color: "var(--ink-3)", width: 18 }}>
          {TYPE_GLYPHS[group.type]}
        </div>
        <div className="serif" style={{ fontSize: 22, fontWeight: 500, lineHeight: 1.1 }}>
          {group.label}
        </div>
        <div style={{ fontSize: 12, color: "var(--ink-3)" }}>
          <span className="mono">{group.sku}</span> · {group.type}
        </div>
      </div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 18, fontSize: 12, color: "var(--ink-3)" }}>
        <div>
          <span className="mono" style={{ color: "var(--ink-2)" }}>{active.length}</span> active
          {group.items.length !== active.length && (
            <span style={{ color: "var(--ink-4)" }}> / {group.items.length} total</span>
          )}
        </div>
        <div>
          <span className="mono" style={{ color: "var(--ink-2)" }}>
            {totalRemaining.toFixed(2).replace(/\.?0+$/, "") || "0"}
          </span>{" "}
          {cfg?.unit ?? "g"} on hand
        </div>
        {lastBuy > 0 && (
          <div>
            last buy{" "}
            <span className="mono" style={{ color: "var(--ink-2)" }}>
              {fmt.dateShort(new Date(lastBuy).toISOString())}
            </span>
          </div>
        )}
      </div>
    </div>
  );
}

function ItemRow({
  i,
  data,
  onSelect,
  indented = false,
}: {
  i: Item;
  data: Bootstrap;
  onSelect: (i: Item) => void;
  indented?: boolean;
}) {
  const bin = data.bins.find((b) => b.id === i.binId);
  const pctRemaining = helpers.pctRemaining(i, TODAY_STR);
  const overdue = helpers.auditOverdue(i, TODAY_STR);
  const sinceCheck = helpers.daysSinceCheck(i, TODAY_STR);
  const last = helpers.lastAudit(i);
  const isInactive = i.status !== "active" && i.status !== "checked-out";
  return (
    <div
      onClick={() => onSelect(i)}
      className="inv-row"
      style={{
        display: "grid",
        gridTemplateColumns: GRID_COLS,
        columnGap: 16,
        padding: indented ? "14px 20px 14px 36px" : "14px 20px",
        borderBottom: "1px solid var(--line)",
        alignItems: "center",
        cursor: "pointer",
        opacity: isInactive ? 0.55 : 1,
        fontSize: 13,
        borderLeft: indented ? "2px solid var(--bg-3)" : "none",
      }}
    >
      <div
        style={{
          fontFamily: "var(--serif)",
          fontSize: 18,
          color: "var(--ink-3)",
          opacity: indented ? 0.5 : 1,
        }}
      >
        {TYPE_GLYPHS[i.type]}
      </div>
      <div style={{ minWidth: 0 }}>
        <div
          style={{
            fontWeight: 500,
            color: "var(--ink)",
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
          }}
        >
          {i.name}
          {i.status === "consumed" && (
            <Pill tone="terra" style={{ marginLeft: 6, fontSize: 10 }}>Consumed</Pill>
          )}
          {i.status === "gone" && (
            <Pill tone="amber" style={{ marginLeft: 6, fontSize: 10 }}>Gone</Pill>
          )}
          {i.status === "checked-out" && (
            <Pill tone="outline" style={{ marginLeft: 6, fontSize: 10 }}>Checked out</Pill>
          )}
          {i.status === "active" && overdue && (
            <Pill tone="amber" style={{ marginLeft: 6, fontSize: 10 }}>Audit due</Pill>
          )}
        </div>
        <div style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--mono)" }}>
          {i.assetId} · {i.sku}
        </div>
      </div>
      <div style={{ color: "var(--ink-2)" }}>{helpers.brandName(data, i.brandId)}</div>
      <div style={{ color: "var(--ink-3)", fontSize: 12 }}>{helpers.shopName(data, i.shopId)}</div>
      <div style={{ fontFamily: "var(--mono)", color: "var(--ink-2)" }}>{i.thc.toFixed(1)}</div>
      <div style={{ fontFamily: "var(--mono)" }}>{fmt.money(i.price)}</div>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "flex-start",
          gap: 4,
        }}
      >
        <div style={{ fontFamily: "var(--mono)", fontSize: 12 }}>{remainingShort(i)}</div>
        {i.status === "active" && i.kind === "bulk" && (
          <div style={{ width: 80, height: 5, background: "var(--bg-3)", borderRadius: 2 }}>
            <div
              style={{
                width: `${pctRemaining * 100}%`,
                height: "100%",
                background:
                  pctRemaining < 0.25
                    ? "var(--terracotta)"
                    : pctRemaining < 0.5
                      ? "var(--amber)"
                      : "var(--sage)",
                borderRadius: 2,
              }}
            />
          </div>
        )}
      </div>
      <div style={{ fontSize: 11, color: overdue ? "var(--terracotta)" : "var(--ink-3)" }}>
        {i.status !== "active" ? (
          <span style={{ fontStyle: "italic" }}>archived</span>
        ) : last ? (
          <span>
            <span className="mono">{sinceCheck}d</span> ago · {last.mode}
          </span>
        ) : (
          <span style={{ fontStyle: "italic" }}>never</span>
        )}
      </div>
      <div style={{ fontSize: 12, color: "var(--ink-3)", display: "flex", alignItems: "center", gap: 6 }}>
        {i.status === "checked-out" ? (
          <span style={{ fontStyle: "italic", color: "var(--sage)" }}>Custody</span>
        ) : bin ? bin.name : <span style={{ fontStyle: "italic" }}>—</span>}
        <span className="inv-row-chevron" style={{ color: "var(--ink-3)", marginLeft: "auto", fontSize: 14 }}>›</span>
      </div>
    </div>
  );
}
