"use client";

/**
 * Product housekeeping on Inventory (plan B, DECISIONS.md 26 Oct 2026): the deleted list with restore and a product's
 * change history (IN-08, the design's `ProductHistory`), merging duplicates (IN-07, `MergePreview` and `MergeReport`)
 * and moving products to shelves by CSV (IN-05, `ShelfAllocationImport`).
 */

import * as React from "react";
import { GitMergeIcon, RotateCcwIcon } from "lucide-react";

import { MergePreview } from "@/components/medora/catalog-ops";
import { ConfirmDialog } from "@/components/medora/confirm-dialog";
import { RecordDrawer } from "@/components/medora/drawer";
import { MergeReport, ProductHistory, ShelfAllocationImport } from "@/components/medora/record-lists";
import { Button } from "@/components/ui/button";
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { toast } from "@/components/ui/toast";
import { ProductsApi, ShelvesApi, type DeletedProductRow, type MergeRow, type MergeSideRow, type ProductChangeRow } from "@/lib/api";
import { count, formatDate, localToday } from "@/lib/format";
import { Loading } from "@/components/medora/loading";

const apiError = (e: unknown, fallback: string): string => {
  const m = (e as { response?: { data?: { message?: string | string[] } } })?.response?.data?.message;
  return Array.isArray(m) ? m.join(" ") : m || fallback;
};

/** A stored time as the local day and hour, e.g. "26 Oct 2026, 14:05". */
const when = (iso: string) => {
  const d = new Date(iso);
  return `${formatDate(localToday(d))}, ${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
};

/** IN-08: deleted products, newest first. A merged-away product can't come back; its stock and history are in the other. */
export function DeletedView({ canRestore, onRestored }: { canRestore: boolean; onRestored: () => void }) {
  const [rows, setRows] = React.useState<DeletedProductRow[] | null>(null);
  const [busy, setBusy] = React.useState<number | null>(null);
  const load = React.useCallback(() => ProductsApi.deleted().then(setRows).catch(() => setRows([])), []);
  React.useEffect(() => void load(), [load]);

  const restore = async (p: DeletedProductRow) => {
    setBusy(p.id);
    try {
      await ProductsApi.restore(p.id);
      toast.add({ title: `${p.name} restored`, description: "Its batches and history are back." });
      await load();
      onRestored();
    } catch (e) {
      toast.add({ type: "error", title: `${p.name} not restored`, description: apiError(e, "Try again.") });
    } finally {
      setBusy(null);
    }
  };

  if (rows === null) return <Loading what="deleted products" shape="list" rows={5} />;
  return (
    <ul className="divide-y divide-[var(--color-border-subtle)] rounded-lg border border-[var(--color-border-panel)] text-sm bg-card">
      {rows.map((p) => (
        <li key={p.id} className="flex flex-wrap items-center gap-3 px-3 py-2">
          <div className="min-w-0 flex-1">
            <p className="font-medium">
              {p.name} {p.code ? <span className="font-mono text-xs text-muted-foreground">{p.code}</span> : null}
            </p>
            <p className="text-xs text-muted-foreground">
              Deleted {when(p.deletedAt)} by {p.deletedBy}
              {p.reason ? `: ${p.reason}` : ""}
            </p>
          </div>
          {canRestore && !p.merged ? (
            <Button size="sm" variant="outline" disabled={busy != null} onClick={() => void restore(p)}>
              {busy === p.id ? <Spinner /> : <RotateCcwIcon data-icon="inline-start" />}
              Restore
            </Button>
          ) : null}
        </li>
      ))}
      {!rows.length ? <li className="px-3 py-6 text-center text-muted-foreground">Nothing deleted.</li> : null}
    </ul>
  );
}

/** IN-07: the merge report. */
export function MergesView() {
  const [rows, setRows] = React.useState<MergeRow[] | null>(null);
  React.useEffect(() => {
    ProductsApi.merges().then(setRows).catch(() => setRows([]));
  }, []);
  if (rows === null) return <Loading what="merges" columns={5} rows={5} />;
  if (!rows.length) return <p className="py-10 text-center text-sm text-muted-foreground">No merges yet. Use Merge into… on a duplicate product.</p>;
  return <MergeReport rows={rows} />;
}

/** IN-08: one product's changes, newest first, recorded from 26 Oct 2026 (Q3). */
export function HistoryDrawer({ product, onClose }: { product: { id: number; name: string }; onClose: () => void }) {
  const [entries, setEntries] = React.useState<ProductChangeRow[] | null>(null);
  React.useEffect(() => {
    ProductsApi.history(product.id).then(setEntries).catch(() => setEntries([]));
  }, [product.id]);
  return (
    <RecordDrawer open onOpenChange={(o) => !o && onClose()} variant="detail" width="lg" title={`History: ${product.name}`} subtitle="Changes to the product record, newest first. Stock movements are in the Inventory log.">
      {entries === null ? (
        <Loading what="the history" shape="list" rows={5} />
      ) : entries.length ? (
        <ProductHistory product={product.name} entries={entries.map((e) => ({ ...e, at: when(e.at) }))} />
      ) : (
        <p className="py-8 text-center text-sm text-muted-foreground">No changes recorded yet. History starts from 26 Oct 2026.</p>
      )}
    </RecordDrawer>
  );
}

/** IN-07: merge `duplicate` into a product chosen here; the kept product keeps its fields unless chosen otherwise (Q1). */
export function MergeDrawer({ duplicate, products, onClose, onDone }: { duplicate: { id: number; name: string }; products: { id: number; name: string; code: string }[]; onClose: () => void; onDone: () => void }) {
  const [keepId, setKeepId] = React.useState("");
  const [preview, setPreview] = React.useState<{ keep: MergeSideRow; merge: MergeSideRow; problem: string | null } | null>(null);
  const [take, setTake] = React.useState<Record<"price" | "taxCode", "keep" | "merge">>({ price: "keep", taxCode: "keep" });
  const [confirming, setConfirming] = React.useState(false);

  React.useEffect(() => {
    setPreview(null);
    if (!keepId) return;
    ProductsApi.mergePreview(Number(keepId), duplicate.id)
      .then(setPreview)
      .catch((e) => toast.add({ type: "error", title: "Couldn't compare the products", description: apiError(e, "Try again.") }));
  }, [keepId, duplicate.id]);

  return (
    <RecordDrawer
      open
      onOpenChange={(o) => !o && onClose()}
      variant="edit"
      width="lg"
      title={`Merge ${duplicate.name}`}
      subtitle="Choose the product to keep. Batches, sales, orders, prices and history move to it, and this one is deleted. It can't be undone."
      footer={
        <>
          <Button variant="outline" onClick={onClose}>
            Cancel
          </Button>
          <Button variant="destructive" disabled={!preview || !!preview.problem} onClick={() => setConfirming(true)}>
            <GitMergeIcon data-icon="inline-start" />
            {preview ? `Merge into ${preview.keep.name}` : "Merge"}
          </Button>
        </>
      }
    >
      <div className="space-y-4">
        <Field>
          <FieldLabel htmlFor="m-keep">Keep</FieldLabel>
          <NativeSelect id="m-keep" value={keepId} onChange={(e) => setKeepId(e.target.value)}>
            <NativeSelectOption value="">Choose the product to keep</NativeSelectOption>
            {products.filter((p) => p.id !== duplicate.id).map((p) => (
              <NativeSelectOption key={p.id} value={p.id}>
                {p.name} ({p.code})
              </NativeSelectOption>
            ))}
          </NativeSelect>
          <FieldDescription>The kept product keeps its name, code and barcode; it takes this one&apos;s barcode only if it has none.</FieldDescription>
        </Field>
        {keepId && !preview ? <Loading what="the merge preview" shape="detail" rows={4} /> : null}
        {preview ? (
          <>
            <MergePreview
              keep={preview.keep}
              merge={preview.merge}
              take={take}
              onTake={(k, v) => setTake((t) => ({ ...t, [k]: v }))}
              // Q1: a product has one barcode; the kept one takes the other's only if it has none
              barcodeAfter={preview.keep.barcode || preview.merge.barcode || "None"}
            />
            {preview.problem ? <p className="rounded-md bg-status-warning-bg px-3 py-2 text-sm text-status-warning-text">{preview.problem}</p> : null}
          </>
        ) : null}
      </div>
      {preview ? (
        <ConfirmDialog
          open={confirming}
          onOpenChange={setConfirming}
          level="B"
          title={`Merge ${preview.merge.name} into ${preview.keep.name}?`}
          consequences={[`${count(preview.merge.stock, "unit")}, ${count(preview.merge.batches, "batch", "batches")} and ${count(preview.merge.sales, "sales line")} move across.`, `${preview.merge.name} disappears from lists; it can't be unmerged.`]}
          reasons={["Duplicate created by mistake", "Same product from a new supplier", "Other"]}
          actionLabel="Merge products"
          busyLabel="Merging…"
          onConfirm={async ({ reason }) => {
            try {
              const r = await ProductsApi.merge(preview.merge.id, preview.keep.id, take, reason);
              toast.add({ title: `${r.ref}: merged`, description: `${r.merged} is now part of ${r.kept}.` });
            } catch (e) {
              throw new Error(apiError(e, "Not merged. Try again."));
            }
            setConfirming(false);
            onDone();
          }}
        />
      ) : null}
    </RecordDrawer>
  );
}

/** IN-05: products to shelves by CSV of item code and shelf; each move is in the product's history. */
export function ShelfImportDrawer({ products, onClose, onDone }: { products: { code: string; name: string }[]; onClose: () => void; onDone: () => void }) {
  const [shelves, setShelves] = React.useState<string[] | null>(null);
  React.useEffect(() => {
    ShelvesApi.list()
      .then((s) => setShelves(s.filter((x) => x.active).map((x) => x.code)))
      .catch(() => setShelves([]));
  }, []);
  return (
    <RecordDrawer open onOpenChange={(o) => !o && onClose()} variant="edit" width="lg" title="Assign shelves" subtitle="Shelves are managed in Settings → Shelves.">
      {shelves === null ? (
        <Loading what="shelves" shape="form" rows={2} />
      ) : shelves.length ? (
        <ShelfAllocationImport
          products={products.map((p) => ({ code: p.code.toUpperCase(), name: p.name }))}
          shelves={shelves}
          onImport={async (rows) => {
            try {
              const r = await ShelvesApi.assign(rows);
              if (r.problems.length) toast.add({ type: "error", title: `${count(r.problems.length, "row")} not applied`, description: r.problems.slice(0, 3).map((p) => `Row ${p.row}: ${p.message}`).join(" ") });
              onDone();
              return r.moved;
            } catch (e) {
              toast.add({ type: "error", title: "Shelves not assigned", description: apiError(e, "Try again.") });
              throw e;
            }
          }}
        />
      ) : (
        <p className="text-sm text-muted-foreground">There are no shelves yet. Add them in Settings → Shelves first.</p>
      )}
    </RecordDrawer>
  );
}
