"use client";

import * as React from "react";
import { ArrowRightIcon } from "lucide-react";

import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { cn } from "@/lib/utils";

import { count, formatDate, unitCount, unitPlural, unitSingular } from "@/lib/format";

import { AsyncBadge, type AsyncState } from "./async-status";
import { Stepper } from "./pos-ops";
import { TONE_BOX } from "./tones";

/** R10 (card 037): an expiry passed as "YYYY-MM-DD" reads "20 Oct 2026"; other text ("Earliest first") is shown as given. */
const shownExpiry = (e: string) => (/^\d{4}-\d\d-\d\d/.test(e) ? formatDate(e) : e || "None");

const n0 = (n: number) => n.toLocaleString("en-US");
const n2 = (n: number) => n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

/* ---------------------------------- 8. Stock conversion ---------------------------------- */

export type ConversionLink = { parent: { name: string; unit: string; stock: number; unitCost: number }; child: { name: string; unit: string; stock: number }; perParent: number };

/**
 * Stock conversion (PRD 3.5, IN-21): break parent units into child units at a fixed rate (1 box = 10 strips).
 * Shows before → after for both products and the cost carried to each child unit, so value is unchanged.
 * Can't convert more parents than are in stock.
 */
export function ConversionPreview({ link, qty, onQty }: { link: ConversionLink; qty: number; onQty: (n: number) => void }) {
  const { parent, child, perParent } = link;
  const childUnits = qty * perParent;
  const childCost = parent.unitCost / perParent;
  const row = (label: string, name: string, before: number, after: number, unit: string) => (
    <tr>
      <th scope="row" className="px-3 py-2 text-left font-normal">
        <span className="text-xs text-muted-foreground">{label}</span>
        <span className="block font-medium">{name}</span>
      </th>
      <td className="px-3 py-2 text-right tabular-nums">
        {unitCount(before, unit)}
      </td>
      <td className="px-1 py-2 text-muted-foreground">
        <ArrowRightIcon className="size-3.5" aria-hidden />
      </td>
      <td className="px-3 py-2 text-right font-semibold tabular-nums">
        {unitCount(after, unit)}
      </td>
    </tr>
  );
  return (
    <div className="space-y-3">
      <div className="flex flex-wrap items-center gap-3 text-sm">
        <span>Convert</span>
        <Stepper value={qty} min={0} max={parent.stock} label={`${unitSingular(parent.unit)} to convert`} onChange={onQty} />
        <span>
          {qty === 1 ? unitSingular(parent.unit) : unitPlural(parent.unit)} of {parent.name} into <span className="font-semibold tabular-nums">{unitCount(childUnits, child.unit)}</span>
        </span>
      </div>
      <p className="text-xs text-muted-foreground">
        1 {unitSingular(parent.unit)} = {unitCount(perParent, child.unit)}. Up to {unitCount(parent.stock, parent.unit)} in stock.
      </p>
      <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
        <table className="w-full border-collapse text-sm">
          <caption className="sr-only">Stock before and after the conversion</caption>
          <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
            <tr>
              <th scope="col" className="px-3 py-2 font-medium">
                Product
              </th>
              <th scope="col" className="px-3 py-2 text-right font-medium">
                Now
              </th>
              <th scope="col" />
              <th scope="col" className="px-3 py-2 text-right font-medium">
                After
              </th>
            </tr>
          </thead>
          <tbody className="divide-y divide-[var(--color-border-subtle)]">
            {row("From", parent.name, parent.stock, parent.stock - qty, parent.unit)}
            {row("To", child.name, child.stock, child.stock + childUnits, child.unit)}
          </tbody>
        </table>
      </div>
      <p className="text-xs text-muted-foreground">
        Cost per {unitSingular(child.unit)}: KES {n2(childCost)} (KES {n2(parent.unitCost)} ÷ {perParent}). Stock value doesn&apos;t change: KES {n2(qty * parent.unitCost)} moves from one product to the other.
      </p>
    </div>
  );
}

/* --------------------------------- 9. Branch transfer --------------------------------- */

export type TransferLine = { id: string; name: string; batch: string; sent: number; received?: number };
export type TransferStage = "draft" | "in-transit" | "received" | "received-short";

export const TRANSFER_BADGE: Record<TransferStage, { state: AsyncState; label: string; severe?: boolean }> = {
  draft: { state: "queued", label: "Draft" },
  "in-transit": { state: "waiting", label: "In transit" },
  received: { state: "done", label: "Received" },
  "received-short": { state: "attention", label: "Received short", severe: true },
};

/**
 * Receiving a branch transfer (PRD 3.8, IN-24): the receiving branch counts what arrived against what was
 * sent. A shortfall needs a note and is reported as lost in transit (IN-25); nobody can receive more than
 * was sent. Stock leaves the sender when it's dispatched and reaches the receiver only when accepted.
 */
export function TransferReceive({ lines, counts, notes, onCount, onNote }: { lines: TransferLine[]; counts: Record<string, number>; notes: Record<string, string>; onCount: (id: string, n: number) => void; onNote: (id: string, s: string) => void }) {
  const short = lines.filter((l) => (counts[l.id] ?? l.sent) < l.sent);
  return (
    <div className="space-y-3">
      <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
        <table className="w-full border-collapse text-sm">
          <caption className="sr-only">Lines on the transfer</caption>
          <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
            <tr>
              <th scope="col" className="px-3 py-2 font-medium">
                Item
              </th>
              <th scope="col" className="px-3 py-2 text-right font-medium">
                Sent
              </th>
              <th scope="col" className="px-3 py-2 font-medium">
                Arrived
              </th>
              <th scope="col" className="px-3 py-2 font-medium">
                Shortfall
              </th>
            </tr>
          </thead>
          <tbody className="divide-y divide-[var(--color-border-subtle)]">
            {lines.map((l) => {
              const got = counts[l.id] ?? l.sent;
              const gap = l.sent - got;
              return (
                <tr key={l.id} className="align-top">
                  <th scope="row" className="px-3 py-2 text-left font-medium">
                    {l.name}
                    <span className="block font-mono text-xs font-normal text-muted-foreground">{l.batch}</span>
                  </th>
                  <td className="px-3 py-2 text-right tabular-nums">{l.sent}</td>
                  <td className="px-3 py-2">
                    <Stepper value={got} max={l.sent} label={`${l.name} arrived`} onChange={(n) => onCount(l.id, n)} />
                  </td>
                  <td className="px-3 py-2">
                    {gap > 0 ? (
                      <div className="space-y-1">
                        <span className="text-xs font-semibold text-status-error-text tabular-nums">{gap} missing</span>
                        <Input aria-label={`What happened to the missing ${l.name}`} placeholder="e.g. Box crushed in transit" value={notes[l.id] ?? ""} onChange={(e) => onNote(l.id, e.target.value)} className="h-8" />
                      </div>
                    ) : (
                      <span className="text-xs text-muted-foreground">None</span>
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
      {short.length ? (
        <p className={cn("rounded-md border px-3 py-2 text-sm", TONE_BOX.warning)}>
          {short.reduce((s, l) => s + l.sent - (counts[l.id] ?? l.sent), 0)} units short on {short.length} {short.length === 1 ? "line" : "lines"}. They&apos;re recorded as lost in transit and appear on the lost transfer report.
        </p>
      ) : null}
    </div>
  );
}

export function TransferBadge({ stage }: { stage: TransferStage }) {
  const b = TRANSFER_BADGE[stage];
  return <AsyncBadge state={b.state} label={b.label} severe={b.severe} className={stage === "in-transit" ? "[&>svg]:animate-none" : undefined} />;
}

/* ------------------------------------ 10. Waste ------------------------------------ */

export type WasteLine = { id: string; name: string; batch: string; expiry: string; qty: number; available: number; unitCost: number; reason: string };

/**
 * Waste write-off lines (PRD 3.4, IN-20): each line a batch, a quantity no more than is in that batch, and a
 * managed reason; valued at the batch's cost. The total at cost is what the approver sees.
 */
export function WasteLines({ lines, reasons, onChange }: { lines: WasteLine[]; reasons: string[]; onChange: (id: string, patch: Partial<WasteLine>) => void }) {
  const total = lines.reduce((s, l) => s + l.qty * l.unitCost, 0);
  return (
    <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
      <table className="w-full border-collapse text-sm">
        <caption className="sr-only">Stock to write off</caption>
        <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
          <tr>
            {["Item and batch", "Quantity", "Reason", "At cost"].map((h) => (
              <th key={h} scope="col" className={cn("px-3 py-2 font-medium", h === "At cost" && "text-right")}>
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-[var(--color-border-subtle)]">
          {lines.map((l) => (
            <tr key={l.id}>
              <th scope="row" className="px-3 py-2 text-left font-medium">
                {l.name}
                <span className="block text-xs font-normal text-muted-foreground">
                  <span className="font-mono">{l.batch}</span> · {l.expiry ? `expires ${shownExpiry(l.expiry)}` : "no expiry"} · {l.available} in batch
                </span>
              </th>
              <td className="px-3 py-2">
                <Stepper value={l.qty} max={l.available} label={`${l.name} to write off`} onChange={(n) => onChange(l.id, { qty: n })} />
              </td>
              <td className="px-3 py-2">
                <NativeSelect size="sm" aria-label={`Reason, ${l.name}`} value={l.reason} onChange={(e) => onChange(l.id, { reason: e.target.value })}>
                  {reasons.map((r) => (
                    <NativeSelectOption key={r} value={r}>
                      {r}
                    </NativeSelectOption>
                  ))}
                </NativeSelect>
              </td>
              <td className="px-3 py-2 text-right tabular-nums">{n2(l.qty * l.unitCost)}</td>
            </tr>
          ))}
        </tbody>
        <tfoot className="border-t-2 border-[var(--color-border-panel)] font-semibold tabular-nums">
          <tr>
            <th scope="row" colSpan={3} className="px-3 py-2 text-left">
              Total at cost, {count(lines.reduce((s, l) => s + l.qty, 0), "unit")}
            </th>
            <td className="px-3 py-2 text-right">KES {n2(total)}</td>
          </tr>
        </tfoot>
      </table>
    </div>
  );
}

/* ---------------------------------- 11. Low stock → PO ---------------------------------- */

export type ReorderRow = { id: number; name: string; stock: number; reorderLevel: number; avgDaily: number; leadDays: number; packSize: number; supplier: string; lastCost: number };

/**
 * Suggested order quantity: enough to cover lead time plus 30 days of sales, less what's in stock, rounded
 * up to whole packs. Never negative.
 */
export function suggestQty(r: ReorderRow) {
  const need = Math.max(0, Math.ceil(r.avgDaily * (r.leadDays + 30) - r.stock));
  return Math.ceil(need / r.packSize) * r.packSize;
}

/**
 * Low stock → purchase order (PRD 3.3): tick items, adjust the suggested quantity, then make one draft PO per
 * supplier. The suggestion says how it was worked out, so the buyer can trust or override it.
 */
export function ReorderPicker({ rows, picked, qty, onPick, onQty }: { rows: ReorderRow[]; picked: Set<number>; qty: Record<number, number>; onPick: (id: number, on: boolean) => void; onQty: (id: number, n: number) => void }) {
  return (
    <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
      <table className="w-full border-collapse text-sm">
        <caption className="sr-only">Items at or below their reorder level</caption>
        <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
          <tr>
            <th scope="col" className="w-10 px-3 py-2">
              <Checkbox aria-label="Select all" checked={rows.every((r) => picked.has(r.id))} indeterminate={rows.some((r) => picked.has(r.id)) && !rows.every((r) => picked.has(r.id))} onCheckedChange={(v) => rows.forEach((r) => onPick(r.id, !!v))} />
            </th>
            {["Item", "Stock / reorder level", "Supplier", "Order", "At last cost"].map((h) => (
              <th key={h} scope="col" className={cn("px-3 py-2 font-medium", (h === "At last cost" || h.startsWith("Stock")) && "text-right")}>
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-[var(--color-border-subtle)]">
          {rows.map((r) => {
            const q = qty[r.id] ?? suggestQty(r);
            return (
              <tr key={r.id} className={cn(picked.has(r.id) && "bg-[var(--color-bg-selected)]")}>
                <td className="px-3 py-2">
                  <Checkbox aria-label={`Order ${r.name}`} checked={picked.has(r.id)} onCheckedChange={(v) => onPick(r.id, !!v)} />
                </td>
                <th scope="row" className="px-3 py-2 text-left font-medium">
                  {r.name}
                  <span className="block text-xs font-normal text-muted-foreground">
                    Sells about {r.avgDaily}/day · {r.leadDays}-day lead time
                  </span>
                </th>
                <td className="px-3 py-2 text-right tabular-nums">
                  <span className={cn(r.stock === 0 && "font-semibold text-status-error-text")}>{n0(r.stock)}</span> / {n0(r.reorderLevel)}
                </td>
                <td className="px-3 py-2">{r.supplier}</td>
                <td className="px-3 py-2">
                  <Stepper value={q} max={99999} label={`${r.name} to order`} onChange={(n) => onQty(r.id, n)} />
                  <span className="mt-0.5 block text-[11px] text-muted-foreground">Suggested {n0(suggestQty(r))}, packs of {r.packSize}</span>
                </td>
                <td className="px-3 py-2 text-right tabular-nums">{n2(q * r.lastCost)}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

/* ------------------------------ 9b. Branch transfer: send ------------------------------ */

export type TransferStockOption = { id: string; name: string; batch: string; expiry: string; available: number };

/**
 * Sending a branch transfer (PRD 3.8, IN-24): from and to must differ; each line is a batch with no more
 * than is available at the source. Earliest expiry is listed first, so the oldest stock moves first. Stock
 * leaves the source when it's dispatched and is "in transit" until the other branch accepts it.
 */
export function TransferSendLines({ options, qty, onQty }: { options: TransferStockOption[]; qty: Record<string, number>; onQty: (id: string, n: number) => void }) {
  const sorted = [...options].sort((a, b) => (a.expiry || "9999").localeCompare(b.expiry || "9999"));
  const units = Object.values(qty).reduce((s, n) => s + n, 0);
  return (
    <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
      <table className="w-full border-collapse text-sm tabular-nums">
        <caption className="sr-only">Stock to send</caption>
        <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
          <tr>
            {["Item and batch", "Expires", "Available", "Send"].map((h) => (
              <th key={h} scope="col" className={cn("px-3 py-2 font-medium", h === "Available" && "text-right")}>
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-[var(--color-border-subtle)]">
          {sorted.map((o) => (
            <tr key={o.id} className={cn((qty[o.id] ?? 0) > 0 && "bg-[var(--color-bg-selected)]")}>
              <th scope="row" className="px-3 py-2 text-left font-medium">
                {o.name}
                <span className="block font-mono text-xs font-normal text-muted-foreground">{o.batch}</span>
              </th>
              <td className="px-3 py-2">{shownExpiry(o.expiry)}</td>
              <td className="px-3 py-2 text-right">{n0(o.available)}</td>
              <td className="px-3 py-2">
                <Stepper value={qty[o.id] ?? 0} max={o.available} label={`${o.name} ${o.batch} to send`} onChange={(n) => onQty(o.id, n)} />
              </td>
            </tr>
          ))}
        </tbody>
        <tfoot className="border-t-2 border-[var(--color-border-panel)] font-semibold">
          <tr>
            <th scope="row" colSpan={3} className="px-3 py-2 text-left">
              Sending
            </th>
            <td className="px-3 py-2">
              {n0(units)} {units === 1 ? "unit" : "units"}
            </td>
          </tr>
        </tfoot>
      </table>
    </div>
  );
}
