"use client";

/**
 * Credit notes (PS-17), on the Medora design system and plan E (DECISIONS.md, 26 Oct 2026): a credit to a registered
 * customer's account without a sale, as the design's direct credit note (`DIRECT_CN_REASONS`, `directCreditProblems`).
 * It waits for approval (`ApprovalQueueItem`) by someone else with Approve on POS/Credit notes, and only then reduces
 * the customer's balance and posts (Sales returns against Accounts receivable). Returns against a sale stay at the
 * till (Past sales → Return). Per-person limits come with the approvals plan (PS-04), so the design's "above KES x
 * needs an Admin" isn't applied yet.
 */

import * as React from "react";

import { ApprovalQueueItem, ApprovalRecord } from "@/components/medora/approval";
import { PanelError } from "@/components/medora/errors";
import { MedoraPageHeader } from "@/components/medora/page-header";
import { DIRECT_CN_REASONS, directCreditProblems } from "@/components/medora/pos-ops";
import { Button } from "@/components/ui/button";
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 { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { toast } from "@/components/ui/toast";
import { CustomersApi, DirectCreditsApi, type DirectCreditRow } from "@/lib/api";
import { formatPhone, formatKES } from "@/lib/format";
import { useMenuPermissions } from "@/lib/permissions";
import { Loading } from "@/components/medora/loading";

const PAGE = "POS/Credit notes";

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

const request = (d: DirectCreditRow) => ({
  id: d.number,
  action: "refund" as const,
  title: `Credit ${kes(d.amount)} to ${d.customer}`,
  why: `${d.reason}${d.details ? `: ${d.details}` : ""}`,
  requestedBy: d.raisedByName ?? "Someone",
  requestedAt: new Date(d.raisedAt),
});

export default function CreditNotesPage() {
  const { can, loaded } = useMenuPermissions();
  const may = (a: string) => loaded && can(PAGE, a);
  const [me, setMe] = React.useState<number | null>(null);
  const [customers, setCustomers] = React.useState<{ id: number; name: string; phone: string }[]>([]);
  const [rows, setRows] = React.useState<DirectCreditRow[] | null>(null);
  const [failed, setFailed] = React.useState(false); // R12 (card 037): a failed load says so, with Try again
  const [view, setView] = React.useState<"Pending" | "decided">("Pending");
  const [f, setF] = React.useState({ customerId: "", amount: "", reason: "", details: "" });
  const [tried, setTried] = React.useState(false);
  const [busy, setBusy] = React.useState(false);

  const load = React.useCallback(async () => {
    try {
      setRows(await DirectCreditsApi.list());
      setFailed(false);
    } catch (e) {
      setRows([]);
      setFailed(true);
      toast.add({ type: "error", title: "Couldn't load credit notes", description: apiError(e, "Try again.") });
    }
  }, []);
  React.useEffect(() => {
    try {
      setMe(JSON.parse(localStorage.getItem("user") || "{}").id ?? null);
    } catch {
      setMe(null);
    }
    void load();
    CustomersApi.getAll()
      .then((cs: { id: number; name: string; phone?: string | null }[]) => setCustomers(cs.map((c) => ({ id: c.id, name: c.name, phone: c.phone ?? "" })).sort((a, b) => a.name.localeCompare(b.name))))
      .catch(() => setCustomers([]));
  }, [load]);

  const customerName = customers.find((c) => String(c.id) === f.customerId)?.name;
  const problems = directCreditProblems({ ...f, customer: customerName }, Infinity);

  const raise = async () => {
    setTried(true);
    if (problems.length) return;
    setBusy(true);
    try {
      const saved: { number: string } = await DirectCreditsApi.raise({ customerId: Number(f.customerId), amount: Number(f.amount.replace(/,/g, "")), reason: f.reason, details: f.details.trim() || undefined });
      toast.add({ title: `${saved.number} sent for approval`, description: "Nothing reaches the customer's account until it's approved." });
      setF({ customerId: "", amount: "", reason: "", details: "" });
      setTried(false);
      setView("Pending");
      await load();
    } catch (e) {
      toast.add({ type: "error", title: "Credit note not raised", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  const decide = async (d: DirectCreditRow, approve: boolean, note?: string) => {
    try {
      await DirectCreditsApi.decide(d.id, { approve, note });
      toast.add({ title: approve ? `${d.number} approved` : `${d.number} declined`, description: approve ? `${kes(d.amount)} credited to ${d.customer}'s account.` : undefined });
      await load();
    } catch (e) {
      toast.add({ type: "error", title: "Not decided", description: apiError(e, "Try again.") });
    }
  };

  const pending = (rows ?? []).filter((r) => r.status === "Pending");
  const decided = (rows ?? []).filter((r) => r.status !== "Pending");

  return (
    <div className="medora mx-auto w-full max-w-6xl space-y-4">
      <MedoraPageHeader title="Credit notes" description="Credit a registered customer without a sale; someone else approves it first." />

      {may("Create") ? (
        <section aria-label="Raise a credit note" className="space-y-3 rounded-lg border border-[var(--color-border-panel)] p-4 bg-card">
          <h2 className="text-sm font-semibold">Direct credit note</h2>
          <div className="grid gap-3">
            <Field>
              <FieldLabel htmlFor="dcn-cust">Customer</FieldLabel>
              <NativeSelect id="dcn-cust" value={f.customerId} onChange={(e) => setF({ ...f, customerId: e.target.value })}>
                <NativeSelectOption value="">Choose a customer</NativeSelectOption>
                {customers.map((c) => (
                  <NativeSelectOption key={c.id} value={String(c.id)}>
                    {c.name}
                    {c.phone ? ` (${formatPhone(c.phone)})` : ""}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="dcn-amount">Amount (KES)</FieldLabel>
              <Input id="dcn-amount" inputMode="decimal" className="tabular-nums" value={f.amount} onChange={(e) => setF({ ...f, amount: e.target.value })} />
            </Field>
            <Field>
              <FieldLabel htmlFor="dcn-reason">Reason</FieldLabel>
              <NativeSelect id="dcn-reason" value={f.reason} onChange={(e) => setF({ ...f, reason: e.target.value })}>
                <NativeSelectOption value="">Choose a reason</NativeSelectOption>
                {DIRECT_CN_REASONS.map((r) => (
                  <NativeSelectOption key={r}>{r}</NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="dcn-details">Details{f.reason === "Other" ? "" : " (optional)"}</FieldLabel>
              <Input id="dcn-details" value={f.details} onChange={(e) => setF({ ...f, details: e.target.value })} />
            </Field>
          </div>
          {tried && problems.length ? (
            <ul role="alert" className="list-disc rounded-md border border-status-error-border bg-status-error-bg py-2 pr-3 pl-8 text-sm text-status-error-text">
              {problems.map((p) => (
                <li key={p}>{p}</li>
              ))}
            </ul>
          ) : null}
          <div className="flex justify-end">
            <Button disabled={busy} onClick={() => void raise()}>
              {busy ? <Spinner /> : null}
              Send for approval
            </Button>
          </div>
        </section>
      ) : null}

      <Tabs value={view} onValueChange={(v) => setView(v as "Pending" | "decided")}>
        <TabsList variant="line" className="w-full justify-start border-b border-border">
          <TabsTrigger value="Pending" className="flex-none">
            Waiting for approval{pending.length ? ` (${pending.length})` : ""}
          </TabsTrigger>
          <TabsTrigger value="decided" className="flex-none">
            Approved and declined
          </TabsTrigger>
        </TabsList>
      </Tabs>

      {failed ? (
        <PanelError framed what="credit notes" onRetry={() => void load()} />
      ) : rows === null ? (
        <Loading what="credit notes" />
      ) : view === "Pending" ? (
        pending.length ? (
          <div className="grid gap-3 lg:grid-cols-2">
            {pending.map((d) =>
              may("Approve") && d.raisedBy !== me ? (
                <ApprovalQueueItem key={d.id} request={request(d)} onApprove={() => void decide(d, true)} onDecline={(note) => void decide(d, false, note)} />
              ) : (
                <div key={d.id} className="space-y-1">
                  <ApprovalRecord request={request(d)} />
                  <p className="text-xs text-muted-foreground">{d.raisedBy === me ? "You raised it, so someone else approves it." : "Someone with Approve on credit notes decides it."}</p>
                </div>
              ),
            )}
          </div>
        ) : (
          <p className="py-10 text-center text-sm text-muted-foreground">Nothing waiting for approval.</p>
        )
      ) : decided.length ? (
        <div className="grid gap-3 lg:grid-cols-2">
          {decided.map((d) => (
            <ApprovalRecord
              key={d.id}
              request={request(d)}
              decision={{
                status: d.status === "Approved" ? "approved" : "declined",
                approver: { id: 0, name: d.decidedByName ?? "", role: "" },
                reason: d.status === "Approved" ? "Credited to the customer's account" : "Declined",
                note: d.decisionNote ?? undefined,
                via: "Manager's device",
                at: new Date(d.decidedAt ?? d.raisedAt),
              }}
            />
          ))}
        </div>
      ) : (
        <p className="py-10 text-center text-sm text-muted-foreground">No credit notes decided yet.</p>
      )}
    </div>
  );
}
