"use client";

/**
 * Loans and salary advances (HR-12, HR-16; plan L). A loan shows the design's `loanSchedule` before it is saved;
 * the API refuses an instalment that leaves less than a third of basic pay. An advance is capped at this month's net
 * pay less advances not yet recovered (the design's `advanceAvailable`, worked out by the API on confirmed rates) and
 * comes off the next monthly payslip in full. Company loans and advances post against the account they were paid from.
 */

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

import { loanSchedule } from "@/components/medora/hr-ops";
import { PanelError } from "@/components/medora/errors";
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 { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { toast } from "@/components/ui/toast";
import { PayrollApi, type AdvanceRow, type LoanRow, type PayrollOptions } from "@/lib/api";

import { Section, addMonths, apiError, human, kes, useAction } from "./shared";
import { Loading } from "@/components/medora/loading";

const num = (s: string) => Number(s.replace(/,/g, ""));

export function LoansView({ today, may }: { today: string; may: (a: string) => boolean }) {
  const [opts, setOpts] = React.useState<PayrollOptions | null>(null);
  const [failed, setFailed] = React.useState(false); // R12 (card 037): a failed load says so, with Try again
  const [loans, setLoans] = React.useState<LoanRow[]>([]);
  const [advances, setAdvances] = React.useState<AdvanceRow[]>([]);
  const [ln, setLn] = React.useState({ employeeId: "", kind: "Company loan" as "Company loan" | "HELB", principal: "", instalment: "", firstMonth: addMonths(today.slice(0, 7), 1), accountId: "", reference: "" });
  const [ad, setAd] = React.useState({ employeeId: "", amount: "", method: "M-Pesa", accountId: "", reference: "", date: today });
  const [limit, setLimit] = React.useState<Awaited<ReturnType<typeof PayrollApi.advanceLimit>> | null>(null);
  const [stopping, setStopping] = React.useState<LoanRow | null>(null);
  const [why, setWhy] = React.useState("");
  const { busy, run } = useAction();

  const load = React.useCallback(() => {
    Promise.all([PayrollApi.options(), PayrollApi.loans(), PayrollApi.advances()])
      .then(([o, l, a]) => {
        setOpts(o);
        setLoans(l);
        setAdvances(a);
        setFailed(false);
      })
      .catch((e) => (setFailed(true), toast.add({ type: "error", title: "Couldn't load loans and advances", description: apiError(e, "Try again.") })));
  }, []);
  React.useEffect(() => load(), [load]);
  React.useEffect(() => {
    setLimit(null);
    if (ad.employeeId) PayrollApi.advanceLimit(Number(ad.employeeId)).then(setLimit).catch(() => setLimit(null));
  }, [ad.employeeId, advances]);

  if (failed) return <PanelError framed what="loans and advances" onRetry={load} />;
  if (!opts)
    return (
      <Loading what="loans and advances" columns={6} rows={3} numeric={[3, 4, 5]} />
    );
  const monthly = opts.employees.filter((e) => e.active && e.payType === "Monthly");
  const emp = monthly.find((e) => String(e.id) === ln.employeeId);
  const schedule = num(ln.principal) > 0 && num(ln.instalment) > 0 && ln.firstMonth ? loanSchedule({ ref: "", kind: ln.kind, employee: emp?.name ?? "", principal: num(ln.principal), instalment: num(ln.instalment), firstMonth: ln.firstMonth, repaid: 0 }) : [];

  const addLoan = async () => {
    const ok = await run(() => PayrollApi.addLoan({ ...ln, employeeId: Number(ln.employeeId), principal: num(ln.principal), instalment: num(ln.instalment), accountId: ln.kind === "Company loan" ? Number(ln.accountId) || undefined : undefined }), `${ln.kind} added`, "Loan not added");
    if (ok) {
      setLn({ ...ln, principal: "", instalment: "", reference: "" });
      load();
    }
  };
  const addAdvance = async () => {
    const ok = await run(() => PayrollApi.addAdvance({ ...ad, employeeId: Number(ad.employeeId), amount: num(ad.amount), accountId: Number(ad.accountId) }), "Advance recorded", "Advance not recorded");
    if (ok) {
      setAd({ ...ad, amount: "", reference: "" });
      load();
    }
  };

  return (
    <div className="space-y-10">
      <Section title="Loans" description="HELB and company loans, taken off each monthly payslip until repaid.">
        {may("Create") ? (
          <div className="grid gap-4 rounded-lg border border-[var(--color-border-panel)] p-3 lg:grid-cols-[1fr_16rem] bg-card">
            <div className="grid items-end gap-2">
              <Field>
                <FieldLabel htmlFor="ln-emp">Employee</FieldLabel>
                <NativeSelect id="ln-emp" value={ln.employeeId} onChange={(e) => setLn({ ...ln, employeeId: e.target.value })}>
                  <NativeSelectOption value="">Choose (monthly staff)</NativeSelectOption>
                  {monthly.map((e) => (
                    <NativeSelectOption key={e.id} value={String(e.id)}>
                      {e.name}
                    </NativeSelectOption>
                  ))}
                </NativeSelect>
              </Field>
              <Field>
                <FieldLabel htmlFor="ln-kind">Kind</FieldLabel>
                <NativeSelect id="ln-kind" value={ln.kind} onChange={(e) => setLn({ ...ln, kind: e.target.value as "Company loan" | "HELB" })}>
                  <NativeSelectOption value="Company loan">Company loan</NativeSelectOption>
                  <NativeSelectOption value="HELB">HELB</NativeSelectOption>
                </NativeSelect>
              </Field>
              <Field>
                <FieldLabel htmlFor="ln-first">First deducted</FieldLabel>
                <Input id="ln-first" type="month" value={ln.firstMonth} onChange={(e) => setLn({ ...ln, firstMonth: e.target.value })} />
              </Field>
              <Field>
                <FieldLabel htmlFor="ln-p">{ln.kind === "HELB" ? "Balance HELB says is owed" : "Amount lent"} (KES)</FieldLabel>
                <Input id="ln-p" inputMode="decimal" value={ln.principal} onChange={(e) => setLn({ ...ln, principal: e.target.value })} />
              </Field>
              <Field>
                <FieldLabel htmlFor="ln-i">Monthly instalment (KES)</FieldLabel>
                <Input id="ln-i" inputMode="decimal" value={ln.instalment} onChange={(e) => setLn({ ...ln, instalment: e.target.value })} />
                {emp?.rate ? <span className="text-xs text-muted-foreground">Basic {kes(emp.rate)}: at least {kes(emp.rate / 3)} must be left after deductions.</span> : null}
              </Field>
              {ln.kind === "Company loan" ? (
                <Field>
                  <FieldLabel htmlFor="ln-acct">Paid from</FieldLabel>
                  <NativeSelect id="ln-acct" value={ln.accountId} onChange={(e) => setLn({ ...ln, accountId: e.target.value })}>
                    <NativeSelectOption value="">Choose the account</NativeSelectOption>
                    {opts.accounts.map((a) => (
                      <NativeSelectOption key={a.id} value={String(a.id)}>
                        {a.code} {a.name}
                      </NativeSelectOption>
                    ))}
                  </NativeSelect>
                </Field>
              ) : (
                <span />
              )}
              <Field>
                <FieldLabel htmlFor="ln-ref">Reference (optional)</FieldLabel>
                <Input id="ln-ref" value={ln.reference} onChange={(e) => setLn({ ...ln, reference: e.target.value })} />
              </Field>
              <Button size="sm" disabled={busy || !ln.employeeId || !schedule.length || (ln.kind === "Company loan" && !ln.accountId)} onClick={() => void addLoan()}>
                Add loan
              </Button>
            </div>
            {schedule.length ? (
              <div className="text-xs">
                <p className="mb-1 font-medium">
                  {schedule.length} payrolls, last in {schedule[schedule.length - 1].month}
                </p>
                <ol className="max-h-48 space-y-0.5 overflow-y-auto tabular-nums text-muted-foreground">
                  {schedule.map((s) => (
                    <li key={s.month} className="flex justify-between gap-2">
                      <span>{s.month}</span>
                      <span>{kes(s.deduction)}</span>
                    </li>
                  ))}
                </ol>
              </div>
            ) : null}
          </div>
        ) : null}
        {loans.length ? (
          <div className="overflow-x-auto rounded-md border border-[var(--color-border-panel)] bg-card">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Loan</TableHead>
                  <TableHead>Employee</TableHead>
                  <TableHead className="text-right">Amount</TableHead>
                  <TableHead className="text-right">Instalment</TableHead>
                  <TableHead className="text-right">Repaid</TableHead>
                  <TableHead className="text-right">Balance</TableHead>
                  <TableHead>Status</TableHead>
                  <TableHead className="w-0" />
                </TableRow>
              </TableHeader>
              <TableBody>
                {loans.map((l) => (
                  <TableRow key={l.id}>
                    <TableCell>
                      {l.number}
                      <span className="block text-xs text-muted-foreground">
                        {l.kind}, from {human(l.firstMonth)}
                      </span>
                    </TableCell>
                    <TableCell>{l.employee}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.principal)}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.instalment)}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.repaid)}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.balance)}</TableCell>
                    <TableCell>
                      {l.status}
                      {l.status === "Active" ? <span className="block text-xs text-muted-foreground">{l.payrollsLeft} payrolls left</span> : l.stopReason ? <span className="block text-xs text-muted-foreground">{l.stopReason}</span> : null}
                    </TableCell>
                    <TableCell>
                      {may("Create") && l.status === "Active" ? (
                        <Button size="sm" variant="ghost" onClick={() => (setStopping(l), setWhy(""))}>
                          <BanIcon data-icon="inline-start" />
                          Stop…
                        </Button>
                      ) : null}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">No loans.</p>
        )}
      </Section>

      <Section title="Salary advances" description="Paid now and taken off the next monthly payslip, up to its net pay.">
        {may("Create") ? (
          <div className="grid items-end gap-2 rounded-lg border border-[var(--color-border-panel)] p-3 bg-card">
            <Field>
              <FieldLabel htmlFor="ad-emp">Employee</FieldLabel>
              <NativeSelect id="ad-emp" value={ad.employeeId} onChange={(e) => setAd({ ...ad, employeeId: e.target.value })}>
                <NativeSelectOption value="">Choose (monthly staff)</NativeSelectOption>
                {monthly.map((e) => (
                  <NativeSelectOption key={e.id} value={String(e.id)}>
                    {e.name}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
              {limit ? (
                <span className={limit.problem ? "text-xs text-status-error-text" : "text-xs text-muted-foreground"}>
                  {limit.problem ?? `Up to ${kes(limit.available)} (net pay about ${kes(limit.netPay)}, ${kes(limit.open)} already advanced).`}
                </span>
              ) : null}
            </Field>
            <Field>
              <FieldLabel htmlFor="ad-amt">Amount (KES)</FieldLabel>
              <Input id="ad-amt" inputMode="decimal" value={ad.amount} onChange={(e) => setAd({ ...ad, amount: e.target.value })} />
            </Field>
            <Field>
              <FieldLabel htmlFor="ad-date">Paid on</FieldLabel>
              <Input id="ad-date" type="date" max={today} value={ad.date} onChange={(e) => setAd({ ...ad, date: e.target.value })} />
            </Field>
            <Field>
              <FieldLabel htmlFor="ad-method">Method</FieldLabel>
              <NativeSelect id="ad-method" value={ad.method} onChange={(e) => setAd({ ...ad, method: e.target.value })}>
                {["M-Pesa", "Bank transfer", "Cash"].map((m) => (
                  <NativeSelectOption key={m} value={m}>
                    {m}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="ad-acct">Paid from</FieldLabel>
              <NativeSelect id="ad-acct" value={ad.accountId} onChange={(e) => setAd({ ...ad, accountId: e.target.value })}>
                <NativeSelectOption value="">Choose the account</NativeSelectOption>
                {opts.accounts.map((a) => (
                  <NativeSelectOption key={a.id} value={String(a.id)}>
                    {a.code} {a.name}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="ad-ref">{ad.method === "M-Pesa" ? "M-Pesa code" : ad.method === "Cash" ? "Voucher (optional)" : "Bank reference"}</FieldLabel>
              <div className="flex gap-2">
                <Input id="ad-ref" value={ad.reference} onChange={(e) => setAd({ ...ad, reference: e.target.value.toUpperCase() })} />
                <Button size="sm" disabled={busy || !ad.employeeId || !ad.amount || !ad.accountId || !!limit?.problem} onClick={() => void addAdvance()}>
                  Record
                </Button>
              </div>
            </Field>
          </div>
        ) : null}
        {advances.length ? (
          <div className="overflow-x-auto rounded-md border border-[var(--color-border-panel)] bg-card">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Advance</TableHead>
                  <TableHead>Employee</TableHead>
                  <TableHead className="text-right">Amount</TableHead>
                  <TableHead>Paid</TableHead>
                  <TableHead>Recovered by</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {advances.map((a) => (
                  <TableRow key={a.id}>
                    <TableCell>
                      {a.number}
                      <span className="block text-xs text-muted-foreground">{human(a.date)}</span>
                    </TableCell>
                    <TableCell>{a.employee}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(a.amount)}</TableCell>
                    <TableCell className="text-sm">
                      {a.method}
                      {a.reference ? `, ${a.reference}` : ""}
                      <span className="block text-xs text-muted-foreground">{a.paidFrom}</span>
                    </TableCell>
                    <TableCell>{a.recoveredBy ?? "Next monthly payroll"}</TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">No salary advances.</p>
        )}
      </Section>

      <Dialog open={!!stopping} onOpenChange={(o) => (!o ? setStopping(null) : null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Stop deducting {stopping?.number}</DialogTitle>
            <DialogDescription>No more instalments come off {stopping?.employee}&apos;s pay. What was repaid stays on the record.</DialogDescription>
          </DialogHeader>
          <Field>
            <FieldLabel htmlFor="ln-why">Why</FieldLabel>
            <Input id="ln-why" value={why} placeholder="e.g. Repaid in cash; HELB cleared" onChange={(e) => setWhy(e.target.value)} />
          </Field>
          <DialogFooter>
            <Button variant="outline" onClick={() => setStopping(null)}>
              Cancel
            </Button>
            <Button
              disabled={busy || why.trim().length < 3}
              onClick={() =>
                void run(() => PayrollApi.stopLoan(stopping!.id, why.trim()), "Loan stopped").then((x) => {
                  if (x) {
                    setStopping(null);
                    load();
                  }
                })
              }
            >
              Stop loan
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
