"use client";

/**
 * Supplier bills (AC-10; plan I): GRNs waiting for their bill (the design's `GrnList`, opening `BillForm`), the bills
 * (`SupplierBills`), clearing a held bill (Approve, not by whoever entered it) and cancelling one entered by mistake.
 */

import * as React from "react";
import { BanIcon, CheckIcon } from "lucide-react";

import { BillForm, GrnList, SupplierBills, billProblems, type BillDraft } from "@/components/medora/goods-in";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { toast } from "@/components/ui/toast";
import { PayablesApi, type SupplierBillRow, type UnbilledGrn } from "@/lib/api";
import { formatDate, formatKES } from "@/lib/format";
import { Loading } from "@/components/medora/loading";

const kes = (n: number) => formatKES(n, { decimals: true });
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;
};

export function BillsView({ bills, unbilled, billsFrom, today, may, reload }: { bills: SupplierBillRow[] | null; unbilled: UnbilledGrn[]; billsFrom: string | null; today: string; may: (a: string) => boolean; reload: () => void }) {
  const [grn, setGrn] = React.useState<UnbilledGrn | null>(null);
  const [draft, setDraft] = React.useState<BillDraft>({ invoiceNo: "", cuNo: "", invoiceDate: today, amount: "", note: "" });
  const [tried, setTried] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [act, setAct] = React.useState<null | { kind: "clear" | "cancel"; id: string }>(null);
  const [text, setText] = React.useState("");

  if (!bills)
    return (
      <Loading what="bills" columns={7} rows={5} toolbar={2} numeric={[4, 5, 6]} />
    );

  const sameSupplier = grn ? bills.filter((b) => b.supplierId === grn.supplierId && b.status !== "Cancelled").map((b) => b.invoiceNo.toUpperCase()) : [];
  const problems = grn ? billProblems(draft, grn.value, sameSupplier) : [];
  const live = bills.filter((b) => b.status !== "Cancelled");
  const held = live.filter((b) => b.held);

  const save = async () => {
    if (!grn) return;
    setTried(true);
    if (problems.length) return;
    setBusy(true);
    try {
      const b = await PayablesApi.createBill({ grnId: grn.id, ...draft });
      toast.add({ title: `${b.no} entered`, description: b.held ? "Held from payment until the difference is cleared." : `Due ${formatDate(b.dueDate)}.` });
      setGrn(null);
      reload();
    } catch (e) {
      toast.add({ type: "error", title: "Bill not entered", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  const run = async () => {
    if (!act) return;
    setBusy(true);
    try {
      const b = act.kind === "clear" ? await PayablesApi.clearBill(Number(act.id), text.trim() || undefined) : await PayablesApi.cancelBill(Number(act.id), text.trim());
      toast.add({ title: act.kind === "clear" ? `${b.no} cleared for payment` : `${b.no} cancelled`, description: act.kind === "cancel" ? "Its posting is reversed; the GRN can be billed again." : undefined });
      setAct(null);
      reload();
    } catch (e) {
      toast.add({ type: "error", title: act.kind === "clear" ? "Not cleared" : "Not cancelled", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="space-y-6">
      {billsFrom ? (
        <section className="space-y-2">
          <h2 className="text-sm font-semibold">Goods received, waiting for the supplier&apos;s bill</h2>
          {unbilled.length ? (
            <GrnList
              grns={unbilled}
              onOpen={(no) => {
                if (!may("Create")) return toast.add({ type: "error", title: "You can't enter supplier bills" });
                const g = unbilled.find((x) => x.no === no) ?? null;
                setGrn(g);
                setTried(false);
                setDraft({ invoiceNo: "", cuNo: g?.cuNo ?? "", invoiceDate: today, amount: "", note: "" });
              }}
            />
          ) : (
            <p className="text-sm text-muted-foreground">Every GRN since {billsFrom} has its bill.</p>
          )}
        </section>
      ) : null}

      <section className="space-y-2">
        <div className="flex flex-wrap items-center justify-between gap-2">
          <h2 className="text-sm font-semibold">Bills</h2>
          {may("Delete") && live.some((b) => b.credited === 0) ? (
            <Button size="sm" variant="ghost" onClick={() => (setAct({ kind: "cancel", id: "" }), setText(""))}>
              <BanIcon data-icon="inline-start" />
              Cancel a bill…
            </Button>
          ) : null}
        </div>
        {held.length ? (
          <div className="space-y-2 rounded-lg border border-[var(--color-border-panel)] p-3 text-sm bg-card">
            <p className="font-medium">Held from payment</p>
            {held.map((b) => (
              <div key={b.id} className="flex flex-wrap items-center justify-between gap-2">
                <span>
                  <span className="font-mono text-xs">{b.no}</span> · {b.supplier}: {kes(b.amount)} against {kes(b.grnValue)} received. {b.held}
                </span>
                {may("Approve") ? (
                  <Button size="sm" variant="outline" onClick={() => (setAct({ kind: "clear", id: String(b.id) }), setText(""))}>
                    <CheckIcon data-icon="inline-start" />
                    Clear for payment
                  </Button>
                ) : null}
              </div>
            ))}
          </div>
        ) : null}
        {live.length ? (
          <SupplierBills today={today} bills={live.map((b) => ({ no: b.no, supplier: b.supplier, invoiceNo: b.invoiceNo, grn: b.grn, invoiceDate: b.invoiceDate, dueDate: b.dueDate, amount: b.amount, grnValue: b.grnValue, paid: b.paid, credited: b.credited, held: b.held }))} />
        ) : (
          <p className="text-sm text-muted-foreground">{billsFrom ? "No bills in these dates." : "Bills are entered once this pharmacy starts entering supplier bills."}</p>
        )}
      </section>

      <Dialog open={!!grn} onOpenChange={(o) => !o && !busy && setGrn(null)}>
        <DialogContent className="sm:max-w-2xl">
          <DialogHeader>
            <DialogTitle>Bill for {grn?.no}</DialogTitle>
            <DialogDescription>The supplier&apos;s invoice for these goods. It is due on their payment terms.</DialogDescription>
          </DialogHeader>
          {grn ? <BillForm grn={grn} termsDays={grn.termsDays} b={draft} onChange={setDraft} problems={problems} tried={tried} /> : null}
          <DialogFooter>
            <Button variant="outline" disabled={busy} onClick={() => setGrn(null)}>
              Cancel
            </Button>
            <Button disabled={busy} onClick={() => void save()}>
              {busy ? <Spinner /> : null}
              Enter bill
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={!!act} onOpenChange={(o) => !o && !busy && setAct(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{act?.kind === "clear" ? "Clear the difference?" : "Cancel a bill"}</DialogTitle>
            <DialogDescription>{act?.kind === "clear" ? "The bill can then be paid in full. Someone other than whoever entered it clears it." : "For a bill entered by mistake. Its posting is reversed and the GRN waits for its bill again. Not once a credit note reduces it."}</DialogDescription>
          </DialogHeader>
          {act?.kind === "cancel" ? (
            <Field>
              <FieldLabel htmlFor="pb-bill">Bill</FieldLabel>
              <NativeSelect id="pb-bill" value={act.id} onChange={(e) => setAct({ kind: "cancel", id: e.target.value })}>
                <NativeSelectOption value="">Choose…</NativeSelectOption>
                {live
                  .filter((b) => b.credited === 0)
                  .map((b) => (
                    <NativeSelectOption key={b.id} value={String(b.id)}>
                      {b.no} · {b.supplier} · inv {b.invoiceNo} · {kes(b.amount)}
                    </NativeSelectOption>
                  ))}
              </NativeSelect>
            </Field>
          ) : null}
          <Field>
            <FieldLabel htmlFor="pb-text">{act?.kind === "clear" ? "Note (optional)" : "Why"}</FieldLabel>
            <Input id="pb-text" value={text} onChange={(e) => setText(e.target.value)} placeholder={act?.kind === "clear" ? "e.g. Supplier confirmed the price rise" : "e.g. Entered against the wrong GRN"} />
          </Field>
          <DialogFooter>
            <Button variant="outline" disabled={busy} onClick={() => setAct(null)}>
              Back
            </Button>
            <Button variant={act?.kind === "cancel" ? "destructive" : "default"} disabled={busy || !act?.id || (act.kind === "cancel" && text.trim().length < 3)} onClick={() => void run()}>
              {busy ? <Spinner /> : null}
              {act?.kind === "clear" ? "Clear for payment" : "Cancel bill"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
