"use client";

import * as React from "react";
import Image from "next/image";

import { cn } from "@/lib/utils";

/*
 * Kenyan statutory deductions, in one place so a rate change is one edit. Working values as understood for
 * pay periods from February 2025 (NSSF year 3, SHIF, Affordable Housing Levy, PAYE bands, with SHIF and the
 * levy deductible before PAYE since December 2024). They must be confirmed by the pharmacy's accountant
 * before payroll is run for real; the UI says so.
 */
export const KE_PAYROLL = {
  effective: "Feb 2025",
  nssf: { rate: 0.06, lowerLimit: 8000, upperLimit: 72000 },
  shif: { rate: 0.0275, minimum: 300 },
  housingLevy: { rate: 0.015 },
  paye: {
    bands: [
      { upTo: 24000, rate: 0.1 },
      { upTo: 32333, rate: 0.25 },
      { upTo: 500000, rate: 0.3 },
      { upTo: 800000, rate: 0.325 },
      { upTo: Infinity, rate: 0.35 },
    ],
    personalRelief: 2400,
  },
} as const;

const r2 = (n: number) => Math.round(n * 100) / 100;

export type PayInput = {
  basic: number;
  allowances: number;
  overtime: number;
  /** HR-17/18: this month's commission and bonuses, taxable with salary. */
  commission?: number;
  bonus?: number;
  otherDeductions: number;
  /** HR-12: HELB and company loan instalments, deducted after tax like an advance. */
  loans?: number;
  loanRefs?: string[];
  /** Salary advances recovered on this run (after tax: an advance is pay already received, not a tax item). */
  advance?: number;
  /** Their references, printed on the payslip so the line traces back to the advance (HR-16). */
  advanceRefs?: string[];
};

export type PayResult = PayInput & {
  gross: number;
  nssf: number;
  shif: number;
  housingLevy: number;
  taxable: number;
  payeBeforeRelief: number;
  paye: number;
  totalDeductions: number;
  net: number;
};

/** Monthly pay for one employee. Every figure is rounded to cents; net = gross − all deductions. */
export function computePay(p: PayInput): PayResult {
  const k = KE_PAYROLL;
  const gross = r2(p.basic + p.allowances + p.overtime + (p.commission ?? 0) + (p.bonus ?? 0));
  const pensionable = Math.min(gross, k.nssf.upperLimit);
  const nssf = r2(pensionable * k.nssf.rate);
  const shif = r2(Math.max(gross * k.shif.rate, gross > 0 ? k.shif.minimum : 0));
  const housingLevy = r2(gross * k.housingLevy.rate);
  const taxable = Math.max(0, r2(gross - nssf - shif - housingLevy));
  let tax = 0;
  let floor = 0;
  for (const b of k.paye.bands) {
    if (taxable <= floor) break;
    tax += (Math.min(taxable, b.upTo) - floor) * b.rate;
    floor = b.upTo;
  }
  const payeBeforeRelief = r2(tax);
  const paye = r2(Math.max(0, tax - k.paye.personalRelief));
  const totalDeductions = r2(nssf + shif + housingLevy + paye + p.otherDeductions + (p.advance ?? 0) + (p.loans ?? 0));
  return { ...p, gross, nssf, shif, housingLevy, taxable, payeBeforeRelief, paye, totalDeductions, net: r2(gross - totalDeductions) };
}

const fmt = new Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
/** Money as the formatting spec shows it everywhere (02-data-display §8.1): "KES 1,250.00". */
export const kes = (n: number) => `KES ${fmt.format(n)}`;

export type Employee = { id: string; name: string; number: string; role: string; kraPin: string; nssfNo: string; shaNo: string; bank: string };

/**
 * Payslip, A4 (HR-08). Black on white for printing; "Confidential pay information" on the slip itself, as
 * on every print of pay data. Print with printElement(el, "a4").
 *
 * Live payroll (plan L) passes the payslip's own `relief` and the confirmed rates' date as `ratesAsAt`, so nothing
 * printed comes from `KE_PAYROLL`; the demo leaves both out.
 */
export const Payslip = React.forwardRef<HTMLDivElement, { employer: { name: string; kraPin: string; address: string }; employee: Employee; period: string; pay: PayResult; payDate: string; relief?: number; ratesAsAt?: string }>(
  function Payslip({ employer, employee, period, pay, payDate, relief = KE_PAYROLL.paye.personalRelief, ratesAsAt = KE_PAYROLL.effective }, ref) {
    const row = (label: string, value: number, strong = false, negative = false) => (
      <tr className={cn("border-b border-neutral-300", strong && "font-bold")}>
        <td className="py-1">{label}</td>
        <td className="py-1 text-right tabular-nums">
          {negative && value ? "−" : ""}
          {kes(value)}
        </td>
      </tr>
    );
    return (
      <div ref={ref} className="mx-auto box-border w-[210mm] bg-white p-[12mm] text-[9pt] leading-[1.35] text-black shadow-md print:w-auto print:p-0 print:shadow-none" aria-label={`Payslip, ${employee.name}, ${period}`}>
        <header className="flex items-start justify-between gap-6 border-b border-black pb-3">
          <div>
            <Image src="/medora-logo.svg" alt="Medora" width={884} height={238} unoptimized className="mb-2 h-[8mm] w-auto grayscale contrast-[1.8]" />
            <p className="text-[10pt] font-bold">{employer.name}</p>
            <p>{employer.address}</p>
            <p>KRA PIN {employer.kraPin}</p>
          </div>
          <div className="text-right">
            <h1 className="text-[16pt] leading-none font-bold uppercase">Payslip</h1>
            <p className="mt-2 font-semibold">{period}</p>
            <p>Paid {payDate}</p>
          </div>
        </header>
        <p className="mt-2 text-[8pt] font-bold uppercase">Confidential pay information</p>
        <dl className="mt-3 grid grid-cols-4 gap-x-4 gap-y-1">
          {[
            ["Employee", employee.name],
            ["Number", employee.number],
            ["Role", employee.role],
            ["KRA PIN", employee.kraPin],
            ["NSSF no", employee.nssfNo],
            ["SHA no", employee.shaNo],
            ["Paid to", employee.bank],
          ].map(([k, v]) => (
            <div key={k}>
              <dt className="text-[7.5pt] uppercase">{k}</dt>
              <dd className="font-semibold">{v}</dd>
            </div>
          ))}
        </dl>
        <div className="mt-5 grid grid-cols-2 gap-8">
          <table className="w-full border-collapse">
            <thead>
              <tr className="border-b border-black text-left text-[8pt] uppercase">
                <th className="py-1">Earnings</th>
                <th className="py-1 text-right">KES</th>
              </tr>
            </thead>
            <tbody>
              {row("Basic pay", pay.basic)}
              {pay.allowances ? row("Allowances", pay.allowances) : null}
              {pay.overtime ? row("Overtime", pay.overtime) : null}
              {pay.commission ? row("Commission", pay.commission) : null}
              {pay.bonus ? row("Bonus", pay.bonus) : null}
              {row("Gross pay", pay.gross, true)}
            </tbody>
          </table>
          <table className="w-full border-collapse">
            <thead>
              <tr className="border-b border-black text-left text-[8pt] uppercase">
                <th className="py-1">Deductions</th>
                <th className="py-1 text-right">KES</th>
              </tr>
            </thead>
            <tbody>
              {row("NSSF", pay.nssf)}
              {row("SHIF", pay.shif)}
              {row("Housing levy", pay.housingLevy)}
              {row("PAYE", pay.paye)}
              {pay.advance ? row(`Salary advance${pay.advanceRefs?.length ? ` (${pay.advanceRefs.join(", ")})` : ""}`, pay.advance) : null}
              {pay.loans ? row(`Loan repayments${pay.loanRefs?.length ? ` (${pay.loanRefs.join(", ")})` : ""}`, pay.loans) : null}
              {pay.otherDeductions ? row("Other deductions", pay.otherDeductions) : null}
              {row("Total deductions", pay.totalDeductions, true)}
            </tbody>
          </table>
        </div>
        <div className="mt-5 flex items-end justify-between gap-6 border-t-2 border-black pt-3">
          <dl className="grid grid-cols-[auto_auto] gap-x-4 text-[8pt] tabular-nums">
            <dt>Taxable pay</dt>
            <dd className="text-right">{kes(pay.taxable)}</dd>
            <dt>Tax before relief</dt>
            <dd className="text-right">{kes(pay.payeBeforeRelief)}</dd>
            <dt>Personal relief</dt>
            <dd className="text-right">{kes(relief)}</dd>
          </dl>
          <p className="text-right">
            <span className="block text-[8pt] uppercase">Net pay</span>
            <span className="text-[16pt] font-bold tabular-nums">{kes(pay.net)}</span>
          </p>
        </div>
        <p className="mt-6 text-[7.5pt]">Statutory rates as at {ratesAsAt}. Questions about this payslip go to your branch administrator.</p>
      </div>
    );
  },
);
