"use client";

/**
 * Scheme claims (AC-13; plan H Q2), as the design's claims example: what each scheme owes (`claimsByScheme`), the
 * claims with `ClaimBadge`, submitting, recording a payment (`ClaimPaymentForm`; writing off a shortfall needs Approve)
 * and marking one rejected (Approve). Claims open themselves when the till takes a scheme's share of a sale.
 */

import * as React from "react";
import { BanknoteIcon, SendIcon, XIcon } from "lucide-react";

import { ClaimBadge, ClaimPaymentForm, claimsByScheme, type Claim, type ClaimStatus } from "@/components/medora/accounts-ops";
import { StatusTag } from "@/components/medora/record-lists";
import { RecordDrawer } from "@/components/medora/drawer";
import { RowActions, type RowAction } from "@/components/medora/row-actions";
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 { Spinner } from "@/components/ui/spinner";
import { toast } from "@/components/ui/toast";
import { ClaimsApi, type ClaimRow } from "@/lib/api";
import { formatDate } from "@/lib/format";
import { cn } from "@/lib/utils";

import { apiError, kes, today } from "./shared";
import { Loading } from "@/components/medora/loading";

export function ClaimsView({ rows, view, onView, reload, may }: { rows: ClaimRow[] | null; view: "open" | "all"; onView: (v: "open" | "all") => void; reload: () => void; may: (a: string) => boolean }) {
  const [paying, setPaying] = React.useState<ClaimRow | null>(null);
  const [rejecting, setRejecting] = React.useState<ClaimRow | null>(null);
  const [reason, setReason] = React.useState("");
  const [busy, setBusy] = React.useState(false);

  const act = async (title: string, fn: () => Promise<unknown>, done: string) => {
    setBusy(true);
    try {
      await fn();
      toast.add({ title: done });
      reload();
      return true;
    } catch (e) {
      toast.add({ type: "error", title, description: apiError(e, "Try again.") });
      return false;
    } finally {
      setBusy(false);
    }
  };

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

  const asClaim = (c: ClaimRow): Claim => ({ ref: c.ref, scheme: c.scheme, member: c.member, sale: c.sale, date: c.date, submitted: c.submitted, claimed: c.claimed, paid: c.paid, status: (c.status === "Cancelled" ? "Rejected" : c.status) as ClaimStatus, reason: c.reason });
  const summary = claimsByScheme(rows.filter((r) => r.status !== "Cancelled").map(asClaim), today());

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-center justify-between gap-2">
        <label className="inline-flex items-center gap-2 text-sm">
          <input type="checkbox" className="size-4" checked={view === "all"} onChange={(e) => onView(e.target.checked ? "all" : "open")} />
          Show paid, rejected and cancelled claims in these dates
        </label>
      </div>
      {summary.length ? (
        <div className="grid gap-3 sm:grid-cols-3">
          {summary.map(([scheme, s]) => (
            <div key={scheme} className="rounded-lg border border-[var(--color-border-panel)] bg-card p-3 text-sm">
              <p className="font-semibold">{scheme}</p>
              <p className="tabular-nums">Due {kes(s.due)}</p>
              <p className="text-xs text-muted-foreground tabular-nums">
                Claimed {kes(s.claimed)} · received {kes(s.paid)}
                {s.oldest ? <span className={cn(s.oldest > 30 && "font-medium text-status-warning-text")}> · oldest waiting {s.oldest} days</span> : null}
              </p>
            </div>
          ))}
        </div>
      ) : null}
      {rows.length ? (
        <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">
            <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
              <tr>
                {["Claim", "Scheme and member", "Sale", "Claimed", "Paid", "Status", ""].map((h, i) => (
                  <th key={i} scope="col" className={cn("px-3 py-2 font-medium", (h === "Claimed" || h === "Paid") && "text-right")}>
                    {h || <span className="sr-only">Actions</span>}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody className="divide-y divide-[var(--color-border-subtle)]">
              {rows.map((c) => {
                const actions: RowAction[] =
                  c.status === "Draft" && may("Update")
                    ? [{ label: "Submit to scheme", icon: SendIcon, onSelect: () => void act("Not submitted", () => ClaimsApi.submit(c.id), `${c.ref} submitted to ${c.scheme}`) }]
                    : c.status === "Submitted" || c.status === "Part paid"
                      ? [
                          ...(may("Update") ? [{ label: "Record payment…", icon: BanknoteIcon, onSelect: () => setPaying(c) }] : []),
                          ...(may("Approve") ? [{ label: "Mark rejected…", icon: XIcon, destructive: true, onSelect: () => (setRejecting(c), setReason("")) }] : []),
                        ]
                      : [];
                return (
                  <tr key={c.id}>
                    <td className="px-3 py-2 font-mono text-xs">
                      {c.ref}
                      <span className="block font-sans text-muted-foreground">
                        {formatDate(c.date)}
                        {c.status === "Draft" && c.submitBy ? <span className={cn(c.submitBy < today() && "font-medium text-status-warning-text")}> · submit by {formatDate(c.submitBy)}</span> : null}
                      </span>
                    </td>
                    <td className="px-3 py-2">
                      {c.scheme}
                      <span className="block text-xs text-muted-foreground">
                        {c.member}
                        {c.memberNo ? `, ${c.memberNo}` : ""}
                      </span>
                    </td>
                    <td className="px-3 py-2 font-mono text-xs">{c.sale}</td>
                    <td className="px-3 py-2 text-right">{kes(c.claimed)}</td>
                    <td className="px-3 py-2 text-right">{c.paid ? kes(c.paid) : "–"}</td>
                    <td className="px-3 py-2">
                      {c.status === "Cancelled" ? <StatusTag status="Cancelled" /> : <ClaimBadge status={c.status} />}
                      {c.reason ? <span className="mt-0.5 block text-xs text-muted-foreground">{c.reason}</span> : null}
                    </td>
                    <td className="px-2 py-2 text-right">
                      <RowActions label={c.ref} actions={actions} />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      ) : (
        <p className="py-10 text-center text-sm text-muted-foreground">
          {view === "open" ? "No claims waiting. A claim opens when the till takes a scheme's share of a member's sale." : "No claims in these dates."}
        </p>
      )}

      {paying ? (
        <RecordDrawer open onOpenChange={(o) => !o && !busy && setPaying(null)} title={`Payment for ${paying.ref}`} subtitle={`${paying.scheme} · ${paying.member}`}>
          <ClaimPaymentForm
            claim={{ ...asClaim(paying), paid: paying.paid + paying.writtenOff }}
            onSave={(p) => {
              if (p.writeOff && !may("Approve")) {
                toast.add({ type: "error", title: "Writing off needs approval", description: "Record what was paid; an administrator can write off the rest." });
                return;
              }
              void act("Payment not recorded", () => ClaimsApi.pay(paying.id, p), `${kes(p.amount)} recorded on ${paying.ref}`).then((ok) => ok && setPaying(null));
            }}
          />
        </RecordDrawer>
      ) : null}

      <Dialog open={!!rejecting} onOpenChange={(o) => !o && !busy && setRejecting(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Mark {rejecting?.ref} rejected?</DialogTitle>
            <DialogDescription>{rejecting ? `${kes(rejecting.due)} still due is written off to Scheme claims written off.` : ""}</DialogDescription>
          </DialogHeader>
          <Field>
            <FieldLabel htmlFor="cl-reason">The scheme&apos;s reason</FieldLabel>
            <Input id="cl-reason" value={reason} onChange={(e) => setReason(e.target.value)} placeholder="e.g. Member not active on date of service" />
          </Field>
          <DialogFooter>
            <Button variant="outline" disabled={busy} onClick={() => setRejecting(null)}>
              Back
            </Button>
            <Button variant="destructive" disabled={busy || reason.trim().length < 3} onClick={() => rejecting && void act("Not rejected", () => ClaimsApi.reject(rejecting.id, reason.trim()), `${rejecting.ref} marked rejected`).then((ok) => ok && setRejecting(null))}>
              {busy ? <Spinner /> : null}
              Mark rejected
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
