"use client";

import * as React from "react";

import { kes } from "@/components/medora/payroll";
import { PrintLogo } from "@/components/medora/print";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";

/*
 * Closing a shift (PS-20): every tender is counted against what the system expects, not just cash. Cash
 * left in the drawer becomes the next shift's float; the rest is what goes to the bank. The Z-report is the
 * printed record of the same figures, signed by the cashier and the supervisor.
 */

export type ShiftFigures = {
  shiftNo: string;
  till: string;
  branch: string;
  cashier: string;
  opened: string;
  closed: string;
  openingCash: number;
  openingMpesa: number;
  sales: { cash: number; mpesa: number; card: number; credit: number };
  cashRefunds: number;
  /** Card 013: refunds sent back by M-Pesa or to the card come off those tenders too. */
  mpesaRefunds?: number;
  cardRefunds?: number;
  drops: { cash: number; mpesa: number };
  transactions: number;
  voids: number;
  returns: number;
};

export function expectedByTender(f: ShiftFigures) {
  const r2 = (n: number) => Math.round(n * 100) / 100;
  return {
    cash: r2(f.openingCash + f.sales.cash - f.cashRefunds - f.drops.cash),
    mpesa: r2(f.openingMpesa + f.sales.mpesa - (f.mpesaRefunds ?? 0) - f.drops.mpesa),
    card: r2(f.sales.card - (f.cardRefunds ?? 0)),
  };
}

export type CloseCount = { cash: string; leftInDrawer: string; mpesa: string; card: string; note: string };

const num = (s: string) => Number(s.replace(/,/g, ""));
const isMoney = (s: string) => /^\d+(\.\d{1,2})?$/.test(s.replace(/,/g, ""));

export function closeProblems(c: CloseCount, f: ShiftFigures, floatMax: number) {
  const p: Partial<Record<keyof CloseCount, string>> = {};
  if (!isMoney(c.cash)) p.cash = "Count the cash in the drawer and enter the total.";
  if (!isMoney(c.mpesa)) p.mpesa = "Enter the M-Pesa till balance from the statement or the till's SMS.";
  if (!isMoney(c.card)) p.card = "Enter the card terminal's batch total (print it from the terminal).";
  if (!isMoney(c.leftInDrawer)) p.leftInDrawer = "Enter the cash staying in the drawer for the next shift (0 if none).";
  else if (isMoney(c.cash) && num(c.leftInDrawer) > num(c.cash)) p.leftInDrawer = "You can't leave more than you counted.";
  else if (num(c.leftInDrawer) > floatMax) p.leftInDrawer = `The float is at most ${kes(floatMax)}; bank the rest.`;
  const e = expectedByTender(f);
  const off = (["cash", "mpesa", "card"] as const).some((k) => isMoney(c[k]) && Math.abs(num(c[k]) - e[k]) > 0.005);
  if (off && !c.note.trim()) p.note = "Something doesn't balance: say what you know about it. The supervisor sees this on the Z-report.";
  return p;
}

const LABEL = { cash: "Cash", mpesa: "M-Pesa", card: "Card" } as const;

function VarianceText({ v }: { v: number | null }) {
  if (v === null) return <span className="text-muted-foreground">Not counted</span>;
  if (Math.abs(v) <= 0.005) return <span className="text-status-success-text">Balanced</span>;
  return <span className="font-medium text-status-error-text">{v > 0 ? `${kes(v)} over` : `${kes(-v)} short`}</span>;
}

export function CloseShiftForm({ figures, count, onChange, problems, show }: { figures: ShiftFigures; count: CloseCount; onChange: (c: CloseCount) => void; problems: Partial<Record<keyof CloseCount, string>>; show: boolean }) {
  const P = show ? problems : {};
  const e = expectedByTender(figures);
  const set = <K extends keyof CloseCount>(k: K, v: CloseCount[K]) => onChange({ ...count, [k]: v });
  const field = (k: keyof CloseCount, label: string, hint: string) => (
    <div className="space-y-1" data-invalid={!!P[k] || undefined}>
      <label htmlFor={`cs-${k}`} className="text-sm font-medium">
        {label}
      </label>
      <Input id={`cs-${k}`} inputMode="decimal" className="tabular-nums" value={count[k]} onChange={(ev) => set(k, ev.target.value)} aria-invalid={!!P[k]} />
      {P[k] ? <p className="text-xs text-status-error-text">{P[k]}</p> : <p className="text-xs text-muted-foreground">{hint}</p>}
    </div>
  );
  const banked = isMoney(count.cash) && isMoney(count.leftInDrawer) ? num(count.cash) - num(count.leftInDrawer) : null;
  return (
    <div className="space-y-4">
      <div className="grid gap-4 sm:grid-cols-2">
        {field("cash", "Cash counted", "Everything in the drawer, notes and coins.")}
        {field("leftInDrawer", "Cash left in the drawer", "Becomes the next shift's opening float.")}
        {field("mpesa", "M-Pesa counted", "Till balance now, from the M-Pesa statement.")}
        {field("card", "Card total", "From the terminal's end-of-day batch slip.")}
      </div>
      <table className="w-full text-sm tabular-nums">
        <thead className="bg-[var(--color-bg-surface-subtle)] text-xs text-muted-foreground">
          <tr>
            <th className="py-1 text-left font-medium">Tender</th>
            <th className="py-1 text-right font-medium">Expected</th>
            <th className="py-1 text-right font-medium">Counted</th>
            <th className="py-1 text-right font-medium">Difference</th>
          </tr>
        </thead>
        <tbody>
          {(["cash", "mpesa", "card"] as const).map((k) => (
            <tr key={k} className="border-t border-[var(--color-border-subtle)]">
              <td className="py-1">{LABEL[k]}</td>
              <td className="py-1 text-right">{kes(e[k])}</td>
              <td className="py-1 text-right">{isMoney(count[k]) ? kes(num(count[k])) : "–"}</td>
              <td className="py-1 text-right">
                <VarianceText v={isMoney(count[k]) ? num(count[k]) - e[k] : null} />
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      {banked !== null ? (
        <p className="text-sm">
          To bank: <strong className="tabular-nums">{kes(banked)}</strong> cash ({kes(num(count.cash))} counted less {kes(num(count.leftInDrawer))} left as float).
        </p>
      ) : null}
      <div className="space-y-1" data-invalid={!!P.note || undefined}>
        <label htmlFor="cs-note" className="text-sm font-medium">
          Note for the supervisor (needed if anything doesn&apos;t balance)
        </label>
        <Input id="cs-note" value={count.note} onChange={(ev) => set("note", ev.target.value)} aria-invalid={!!P.note} />
        {P.note ? <p className="text-xs text-status-error-text">{P.note}</p> : null}
      </div>
    </div>
  );
}

/** 80 mm Z-report: the shift's printed record. Print with printElement(el, "receipt-80"). */
export const ZReport = React.forwardRef<HTMLDivElement, { figures: ShiftFigures; count: { cash: number; leftInDrawer: number; mpesa: number; card: number; note?: string }; printedAt: string }>(function ZReport({ figures: f, count: c, printedAt }, ref) {
  const e = expectedByTender(f);
  const row = (k: string, v: string, strong?: boolean) => (
    <div className={cn("flex justify-between gap-2", strong && "font-bold")}>
      <span>{k}</span>
      <span className="tabular-nums">{v}</span>
    </div>
  );
  const diff = (counted: number, expected: number) => {
    const d = Math.round((counted - expected) * 100) / 100;
    return d === 0 ? "0.00" : d > 0 ? `+${kes(d)}` : `-${kes(-d)}`;
  };
  const totalSales = f.sales.cash + f.sales.mpesa + f.sales.card + f.sales.credit;
  return (
    <div ref={ref} className="mx-auto w-[302px] border border-border bg-white p-3 font-mono text-[11px] leading-4 text-black" aria-label={`Z-report ${f.shiftNo}`}>
      <div className="text-center">
        <PrintLogo className="mx-auto mb-1 h-6" />
        <p className="font-bold">Z-REPORT</p>
        <p>
          {f.branch} · {f.till}
        </p>
        <p>Shift {f.shiftNo}</p>
      </div>
      <div className="my-2 border-t border-dashed border-black" />
      {row("Cashier", f.cashier)}
      {row("Opened", f.opened)}
      {row("Closed", f.closed)}
      <div className="my-2 border-t border-dashed border-black" />
      <p className="font-bold">SALES</p>
      {row("Cash", kes(f.sales.cash))}
      {row("M-Pesa", kes(f.sales.mpesa))}
      {row("Card", kes(f.sales.card))}
      {row("Credit (on account)", kes(f.sales.credit))}
      {row("Total sales", kes(totalSales), true)}
      {row("Transactions", String(f.transactions))}
      {row("Returns / voids", `${f.returns} / ${f.voids}`)}
      <div className="my-2 border-t border-dashed border-black" />
      <p className="font-bold">CASH</p>
      {row("Opening float", kes(f.openingCash))}
      {row("+ Cash sales", kes(f.sales.cash))}
      {row("- Cash refunds", kes(f.cashRefunds))}
      {row("- Cash drops", kes(f.drops.cash))}
      {row("Expected", kes(e.cash), true)}
      {row("Counted", kes(c.cash))}
      {row("Difference", diff(c.cash, e.cash), true)}
      {row("Left as float", kes(c.leftInDrawer))}
      {row("To bank", kes(c.cash - c.leftInDrawer), true)}
      <div className="my-2 border-t border-dashed border-black" />
      <p className="font-bold">M-PESA AND CARD</p>
      {f.mpesaRefunds ? row("- M-Pesa refunds", kes(f.mpesaRefunds)) : null}
      {f.cardRefunds ? row("- Card refunds", kes(f.cardRefunds)) : null}
      {row("M-Pesa expected", kes(e.mpesa))}
      {row("M-Pesa counted", kes(c.mpesa))}
      {row("Difference", diff(c.mpesa, e.mpesa), true)}
      {row("Card expected", kes(e.card))}
      {row("Card batch total", kes(c.card))}
      {row("Difference", diff(c.card, e.card), true)}
      {c.note ? (
        <>
          <div className="my-2 border-t border-dashed border-black" />
          <p>Note: {c.note}</p>
        </>
      ) : null}
      <div className="my-2 border-t border-dashed border-black" />
      <p className="mt-4">Cashier ____________________</p>
      <p className="mt-4">Supervisor _________________</p>
      <p className="mt-3 text-center">Printed {printedAt}</p>
    </div>
  );
});
