"use client";

/**
 * What goes into payslips (plan L): allowances and deductions, one-off or monthly (HR-13, HR-14, the design's
 * `appliesTo`), bonuses and commissions (HR-17, the design's `bonusProblems`), and overtime, casual hours and piece
 * work (HR-10, HR-11, the design's `hoursWorked`). Anything an approved run has paid is locked.
 */

import * as React from "react";
import { PlusIcon, Trash2Icon } from "lucide-react";

import { BONUS_TYPES, bonusProblems } from "@/components/medora/bonuses";
import { hoursWorked } from "@/components/medora/hr-ops";
import { PanelError } from "@/components/medora/errors";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
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 BonusRow, type PayItemRow, type PayrollOptions, type WorkLogRow } from "@/lib/api";

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

function EmployeeSelect({ id, value, onChange, employees }: { id: string; value: string; onChange: (v: string) => void; employees: PayrollOptions["employees"] }) {
  return (
    <NativeSelect id={id} value={value} onChange={(e) => onChange(e.target.value)}>
      <NativeSelectOption value="">Choose the employee</NativeSelectOption>
      {employees.map((e) => (
        <NativeSelectOption key={e.id} value={String(e.id)}>
          {e.name} ({e.payType})
        </NativeSelectOption>
      ))}
    </NativeSelect>
  );
}

export function RecordsView({ 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 [items, setItems] = React.useState<PayItemRow[]>([]);
  const [bonuses, setBonuses] = React.useState<BonusRow[]>([]);
  const [logs, setLogs] = React.useState<WorkLogRow[]>([]);
  const month = today.slice(0, 7);
  const [range, setRange] = React.useState({ from: `${month}-01`, to: today });
  const { busy, run } = useAction();

  const load = React.useCallback(() => {
    Promise.all([PayrollApi.options(), PayrollApi.items(), PayrollApi.bonuses(), PayrollApi.logs(range)])
      .then(([o, i, b, l]) => {
        setOpts(o);
        setItems(i);
        setBonuses(b);
        setLogs(l);
        setFailed(false);
      })
      .catch((e) => (setFailed(true), toast.add({ type: "error", title: "Couldn't load pay records", description: apiError(e, "Try again.") })));
  }, [range]);
  React.useEffect(() => load(), [load]);

  const [it, setIt] = React.useState({ employeeId: "", kind: "Allowance" as "Allowance" | "Deduction", category: "", amount: "", recurring: true, fromMonth: month, untilMonth: "", taxable: true });
  const [bn, setBn] = React.useState({ employee: "", month, type: "" as (typeof BONUS_TYPES)[number] | "" | "Commission", description: "", amount: "" });
  const [bnTried, setBnTried] = React.useState(false);
  const [lg, setLg] = React.useState({ employeeId: "", kind: "Overtime" as "Overtime" | "Casual" | "Piece", date: today, timeIn: "", timeOut: "", pieces: "", rate: "" });

  if (failed) return <PanelError framed what="pay records" onRetry={load} />;
  if (!opts)
    return (
      <Loading what="pay records" columns={7} rows={4} numeric={[4]} />
    );
  const active = opts.employees.filter((e) => e.active);
  const monthly = active.filter((e) => e.payType === "Monthly");
  const logEmployees = active.filter((e) => e.payType === (lg.kind === "Overtime" ? "Monthly" : lg.kind === "Casual" ? "Casual (hourly)" : "Piece rate"));
  const h = lg.kind !== "Piece" ? hoursWorked(lg.timeIn, lg.timeOut) : null;
  const bnProblems = bonusProblems({ employee: bn.employee, month: bn.month, type: bn.type === "Commission" ? "Other" : bn.type, description: bn.description, amount: bn.amount }, opts.closedMonths);

  const addItem = async () => {
    const ok = await run(() => PayrollApi.addItem({ ...it, employeeId: Number(it.employeeId), amount: it.amount.replace(/,/g, ""), untilMonth: it.recurring ? it.untilMonth || null : null }), `${it.kind} added`);
    if (ok) {
      setIt({ ...it, amount: "", category: "" });
      load();
    }
  };
  const addBonus = async () => {
    setBnTried(true);
    if (Object.keys(bnProblems).length) return;
    const ok = await run(() => PayrollApi.addBonus({ employeeId: Number(bn.employee), month: bn.month, type: bn.type, description: bn.description, amount: bn.amount.replace(/,/g, "") }), `${bn.type} added to ${human(bn.month)}`);
    if (ok) {
      setBn({ ...bn, description: "", amount: "" });
      setBnTried(false);
      load();
    }
  };
  const addLog = async () => {
    const ok = await run(() => PayrollApi.addLog({ ...lg, employeeId: Number(lg.employeeId), pieces: lg.pieces || undefined, rate: lg.rate }), "Logged");
    if (ok) {
      setLg({ ...lg, timeIn: "", timeOut: "", pieces: "" });
      load();
    }
  };

  return (
    <div className="space-y-10">
      <Section title="Allowances and deductions" description="Monthly items repeat until their last month; one-off items are paid once.">
        {may("Create") ? (
          <div className="grid items-end gap-2 rounded-lg border border-[var(--color-border-panel)] p-3 bg-card">
            <Field>
              <FieldLabel htmlFor="pi-emp">Employee</FieldLabel>
              <EmployeeSelect id="pi-emp" value={it.employeeId} onChange={(v) => setIt({ ...it, employeeId: v })} employees={monthly} />
            </Field>
            <Field>
              <FieldLabel htmlFor="pi-kind">Kind</FieldLabel>
              <NativeSelect id="pi-kind" value={it.kind} onChange={(e) => setIt({ ...it, kind: e.target.value as "Allowance" | "Deduction", category: "" })}>
                <NativeSelectOption value="Allowance">Allowance</NativeSelectOption>
                <NativeSelectOption value="Deduction">Deduction</NativeSelectOption>
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="pi-cat">Category</FieldLabel>
              <NativeSelect id="pi-cat" value={it.category} onChange={(e) => setIt({ ...it, category: e.target.value })}>
                <NativeSelectOption value="">Choose</NativeSelectOption>
                {opts.categories[it.kind].map((c) => (
                  <NativeSelectOption key={c} value={c}>
                    {c}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="pi-amt">Amount (KES)</FieldLabel>
              <Input id="pi-amt" inputMode="decimal" value={it.amount} onChange={(e) => setIt({ ...it, amount: e.target.value })} />
            </Field>
            <label className="flex items-center gap-2 text-sm">
              <Checkbox checked={it.recurring} onCheckedChange={(c) => setIt({ ...it, recurring: c === true })} />
              Every month
            </label>
            <Field>
              <FieldLabel htmlFor="pi-from">{it.recurring ? "First month" : "Month"}</FieldLabel>
              <Input id="pi-from" type="month" value={it.fromMonth} onChange={(e) => setIt({ ...it, fromMonth: e.target.value })} />
            </Field>
            {it.recurring ? (
              <Field>
                <FieldLabel htmlFor="pi-until">Last month (optional)</FieldLabel>
                <Input id="pi-until" type="month" value={it.untilMonth} onChange={(e) => setIt({ ...it, untilMonth: e.target.value })} />
              </Field>
            ) : (
              <span />
            )}
            <div className="flex items-center justify-between gap-2">
              {it.kind === "Allowance" ? (
                <label className="flex items-center gap-2 text-sm">
                  <Checkbox checked={it.taxable} onCheckedChange={(c) => setIt({ ...it, taxable: c === true })} />
                  Taxable
                </label>
              ) : (
                <span />
              )}
              <Button size="sm" disabled={busy || !it.employeeId || !it.category || !it.amount} onClick={() => void addItem()}>
                <PlusIcon data-icon="inline-start" />
                Add
              </Button>
            </div>
          </div>
        ) : null}
        {items.length ? (
          <div className="overflow-x-auto rounded-md border border-[var(--color-border-panel)] bg-card">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Employee</TableHead>
                  <TableHead>Item</TableHead>
                  <TableHead>When</TableHead>
                  <TableHead className="text-right">Amount</TableHead>
                  <TableHead className="w-0" />
                </TableRow>
              </TableHeader>
              <TableBody>
                {items.map((i) => {
                  const ended = i.untilMonth && i.untilMonth < today.slice(0, 7);
                  return (
                    <TableRow key={i.id} className={ended ? "text-muted-foreground" : undefined}>
                      <TableCell>{i.employee}</TableCell>
                      <TableCell>
                        {i.kind}: {i.category}
                        {i.kind === "Allowance" && !i.taxable ? <span className="block text-xs text-muted-foreground">Not taxed</span> : null}
                      </TableCell>
                      <TableCell className="text-sm">{i.recurring ? `Monthly from ${human(i.fromMonth)}${i.untilMonth ? ` to ${human(i.untilMonth)}` : ""}` : human(i.fromMonth)}</TableCell>
                      <TableCell className="text-right tabular-nums">{i.kind === "Deduction" ? `−${kes(i.amount)}` : kes(i.amount)}</TableCell>
                      <TableCell className="whitespace-nowrap text-right">
                        {may("Create") && !i.paidIn ? (
                          <Button size="icon-sm" variant="ghost" aria-label={`Remove ${i.category} for ${i.employee}`} disabled={busy} onClick={() => void run(() => PayrollApi.endItem(i.id), "Removed").then(load)}>
                            <Trash2Icon />
                          </Button>
                        ) : may("Create") && i.recurring && !ended ? (
                          <Button size="sm" variant="ghost" disabled={busy} onClick={() => void run(() => PayrollApi.endItem(i.id, addMonths(today.slice(0, 7), -1) < i.fromMonth ? i.fromMonth : addMonths(today.slice(0, 7), -1)), "Ended after last month").then(load)}>
                            End after last month
                          </Button>
                        ) : null}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">No allowances or deductions yet.</p>
        )}
      </Section>

      <Section title="Bonuses and commissions" description="Paid with the month's payroll and taxed with salary. A month whose payroll is approved takes no more.">
        {may("Create") ? (
          <div className="grid items-end gap-2 rounded-lg border border-[var(--color-border-panel)] p-3 sm:grid-cols-5 bg-card">
            <Field data-invalid={(bnTried && !!bnProblems.employee) || undefined}>
              <FieldLabel htmlFor="bn-emp">Employee</FieldLabel>
              <EmployeeSelect id="bn-emp" value={bn.employee} onChange={(v) => setBn({ ...bn, employee: v })} employees={monthly} />
            </Field>
            <Field data-invalid={(bnTried && !!bnProblems.month) || undefined}>
              <FieldLabel htmlFor="bn-month">Month</FieldLabel>
              <Input id="bn-month" type="month" value={bn.month} onChange={(e) => setBn({ ...bn, month: e.target.value })} />
            </Field>
            <Field data-invalid={(bnTried && !!bnProblems.type) || undefined}>
              <FieldLabel htmlFor="bn-type">Type</FieldLabel>
              <NativeSelect id="bn-type" value={bn.type} onChange={(e) => setBn({ ...bn, type: e.target.value as typeof bn.type })}>
                <NativeSelectOption value="">Choose</NativeSelectOption>
                {[...BONUS_TYPES.filter((t) => t !== "Other"), "Commission", "Other"].map((t) => (
                  <NativeSelectOption key={t} value={t}>
                    {t}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
            </Field>
            <Field data-invalid={(bnTried && !!bnProblems.description) || undefined}>
              <FieldLabel htmlFor="bn-desc">For</FieldLabel>
              <Input id="bn-desc" value={bn.description} onChange={(e) => setBn({ ...bn, description: e.target.value })} />
            </Field>
            <Field data-invalid={(bnTried && !!bnProblems.amount) || undefined}>
              <FieldLabel htmlFor="bn-amt">Amount (KES)</FieldLabel>
              <div className="flex gap-2">
                <Input id="bn-amt" inputMode="decimal" value={bn.amount} onChange={(e) => setBn({ ...bn, amount: e.target.value })} />
                <Button size="sm" disabled={busy} onClick={() => void addBonus()}>
                  Add
                </Button>
              </div>
            </Field>
            {bnTried && Object.keys(bnProblems).length ? <p className="text-xs text-status-error-text sm:col-span-5">{Object.values(bnProblems).join(" ")}</p> : null}
          </div>
        ) : null}
        {bonuses.length ? (
          <div className="overflow-x-auto rounded-md border border-[var(--color-border-panel)] bg-card">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Month</TableHead>
                  <TableHead>Employee</TableHead>
                  <TableHead>Type</TableHead>
                  <TableHead className="text-right">Amount</TableHead>
                  <TableHead>Paid by</TableHead>
                  <TableHead className="w-0" />
                </TableRow>
              </TableHeader>
              <TableBody>
                {bonuses.map((b) => (
                  <TableRow key={b.id}>
                    <TableCell>{human(b.month)}</TableCell>
                    <TableCell>{b.employee}</TableCell>
                    <TableCell>
                      {b.type}
                      <span className="block text-xs text-muted-foreground">{b.description}</span>
                    </TableCell>
                    <TableCell className="text-right tabular-nums">{kes(b.amount)}</TableCell>
                    <TableCell>{b.paidBy ?? "Waiting"}</TableCell>
                    <TableCell>
                      {may("Create") && !b.paidBy ? (
                        <Button size="icon-sm" variant="ghost" aria-label={`Remove ${b.type} for ${b.employee}`} disabled={busy} onClick={() => void run(() => PayrollApi.removeBonus(b.id), "Removed").then(load)}>
                          <Trash2Icon />
                        </Button>
                      ) : null}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">No bonuses or commissions.</p>
        )}
      </Section>

      <Section
        title="Overtime, casual hours and piece work"
        description="Overtime is paid with the monthly run; casual hours and pieces by their own runs."
      >
        {may("Create") ? (
          <div className="grid items-end gap-2 rounded-lg border border-[var(--color-border-panel)] p-3 sm:grid-cols-6 bg-card">
            <Field>
              <FieldLabel htmlFor="lg-kind">What</FieldLabel>
              <NativeSelect id="lg-kind" value={lg.kind} onChange={(e) => setLg({ ...lg, kind: e.target.value as typeof lg.kind, employeeId: "" })}>
                <NativeSelectOption value="Overtime">Overtime</NativeSelectOption>
                <NativeSelectOption value="Casual">Casual hours</NativeSelectOption>
                <NativeSelectOption value="Piece">Piece work</NativeSelectOption>
              </NativeSelect>
            </Field>
            <Field>
              <FieldLabel htmlFor="lg-emp">Employee</FieldLabel>
              <EmployeeSelect id="lg-emp" value={lg.employeeId} onChange={(v) => setLg({ ...lg, employeeId: v })} employees={logEmployees} />
            </Field>
            <Field>
              <FieldLabel htmlFor="lg-date">Date</FieldLabel>
              <Input id="lg-date" type="date" max={today} value={lg.date} onChange={(e) => setLg({ ...lg, date: e.target.value })} />
            </Field>
            {lg.kind === "Piece" ? (
              <Field>
                <FieldLabel htmlFor="lg-pcs">Pieces</FieldLabel>
                <Input id="lg-pcs" inputMode="numeric" value={lg.pieces} onChange={(e) => setLg({ ...lg, pieces: e.target.value })} />
              </Field>
            ) : (
              <div className="grid grid-cols-2 gap-1">
                <Field>
                  <FieldLabel htmlFor="lg-in">In</FieldLabel>
                  <Input id="lg-in" type="time" value={lg.timeIn} onChange={(e) => setLg({ ...lg, timeIn: e.target.value })} />
                </Field>
                <Field>
                  <FieldLabel htmlFor="lg-out">Out</FieldLabel>
                  <Input id="lg-out" type="time" value={lg.timeOut} onChange={(e) => setLg({ ...lg, timeOut: e.target.value })} />
                </Field>
              </div>
            )}
            <Field>
              <FieldLabel htmlFor="lg-rate">{lg.kind === "Piece" ? "Rate a piece" : "Rate an hour"}</FieldLabel>
              <Input id="lg-rate" inputMode="decimal" placeholder={lg.kind === "Overtime" ? "Required" : "Their rate"} value={lg.rate} onChange={(e) => setLg({ ...lg, rate: e.target.value })} />
            </Field>
            <div className="space-y-1">
              {h ? (
                <p className={h.hours > 16 ? "text-xs font-medium text-status-error-text" : "text-xs text-muted-foreground"}>
                  {h.hours} h{h.overnight ? ", overnight" : ""}
                  {h.hours > 16 ? ": over 16 h, check the times" : ""}
                </p>
              ) : null}
              <Button size="sm" disabled={busy || !lg.employeeId || (h != null && h.hours > 16)} onClick={() => void addLog()}>
                <PlusIcon data-icon="inline-start" />
                Log
              </Button>
            </div>
          </div>
        ) : null}
        {/* One container (data table spec §1): the dates in the table's toolbar, the empty state inside */}
        <div className="overflow-hidden rounded-md border border-[var(--color-border-panel)] bg-card">
          <div className="flex flex-wrap items-center gap-2 border-b border-[var(--color-border-subtle)] p-3">
            <Input aria-label="From" type="date" className="w-40" value={range.from} onChange={(e) => setRange({ ...range, from: e.target.value })} />
            <Input aria-label="To" type="date" className="w-40" value={range.to} onChange={(e) => setRange({ ...range, to: e.target.value })} />
          </div>
        {logs.length ? (
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Date</TableHead>
                  <TableHead>Employee</TableHead>
                  <TableHead>What</TableHead>
                  <TableHead className="text-right">Hours or pieces</TableHead>
                  <TableHead className="text-right">Rate</TableHead>
                  <TableHead className="text-right">Amount</TableHead>
                  <TableHead>Paid by</TableHead>
                  <TableHead className="w-0" />
                </TableRow>
              </TableHeader>
              <TableBody>
                {logs.map((l) => (
                  <TableRow key={l.id} className={l.paidBy ? "text-muted-foreground" : undefined}>
                    <TableCell className="whitespace-nowrap">{human(l.date)}</TableCell>
                    <TableCell>{l.employee}</TableCell>
                    <TableCell>
                      {l.kind}
                      {l.timeIn ? <span className="block text-xs text-muted-foreground">{l.timeIn}–{l.timeOut}</span> : null}
                    </TableCell>
                    <TableCell className="text-right tabular-nums">{l.kind === "Piece" ? l.pieces : l.hours}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.rate)}</TableCell>
                    <TableCell className="text-right tabular-nums">{kes(l.amount)}</TableCell>
                    <TableCell>{l.paidBy ?? "Waiting"}</TableCell>
                    <TableCell>
                      {may("Create") && !l.paidBy ? (
                        <Button size="icon-sm" variant="ghost" aria-label={`Remove the log for ${l.employee} on ${human(l.date)}`} disabled={busy} onClick={() => void run(() => PayrollApi.removeLog(l.id), "Removed").then(load)}>
                          <Trash2Icon />
                        </Button>
                      ) : null}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        ) : (
          <p className="px-3 py-8 text-center text-sm text-muted-foreground">Nothing logged for these dates.</p>
        )}
        </div>
      </Section>
    </div>
  );
}
