"use client";

import * as React from "react";
import { InfoIcon, SearchIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { cn } from "@/lib/utils";

import { RowActions, type RowAction } from "./row-actions";
import { TONE_BOX } from "./tones";

/*
 * Tax codes (PRD 9.4, ST-07, PS-07, Phase 1 item 1.5). Codes match KRA eTIMS tax types; each product carries
 * one, and the till and VAT report use it instead of the hard-coded 16%. Prices in Medora are VAT-exclusive
 * (total = subtotal + VAT), so VAT is worked out per code on the taxable amount.
 */

export type TaxKind = "Standard" | "Reduced" | "Zero-rated" | "Exempt" | "Non-VAT";

export type TaxCode = {
  code: string;
  name: string;
  kind: TaxKind;
  /** Percent, e.g. 16. */
  rate: number;
  /** ISO date the current rate applies from. */
  effectiveFrom: string;
  /** A scheduled change: the rate from a future date. Past sales keep the rate they were sold at. */
  next?: { rate: number; from: string };
  /** Products using it: a code in use can't be deleted. */
  products: number;
  /** Defined by KRA eTIMS: the letter and kind can't change. */
  etims?: boolean;
};

const pct = (r: number) => `${Number.isInteger(r) ? r : r.toFixed(1)}%`;

/** "B" pill used on cart lines, receipts and lists. */
export function TaxBadge({ code, className }: { code: string; className?: string }) {
  return (
    <span className={cn("inline-flex size-5 shrink-0 items-center justify-center rounded-sm border border-[var(--color-border-panel)] bg-[var(--color-bg-surface-subtle)] font-mono text-[11px] font-semibold text-[var(--color-fg-secondary-strong)]", className)} aria-label={`tax code ${code}`}>
      {code}
    </span>
  );
}

/** Tax codes list for Settings → 9.4. Actions come from the caller, so permissions decide what's offered. */
export function TaxCodesTable({ codes, actionsFor, formatDate }: { codes: TaxCode[]; actionsFor: (c: TaxCode) => RowAction[]; formatDate: (iso: string) => string }) {
  return (
    <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
      <table className="w-full border-collapse text-sm">
        <caption className="sr-only">Tax codes</caption>
        <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
          <tr>
            {["Code", "Name", "Kind", "Rate", "Products", ""].map((h, i) => (
              <th key={i} scope="col" className={cn("px-3 py-2 font-medium", (h === "Rate" || h === "Products") && "text-right")}>
                {h || <span className="sr-only">Actions</span>}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-[var(--color-border-subtle)]">
          {codes.map((c) => (
            <tr key={c.code}>
              <td className="px-3 py-2">
                <TaxBadge code={c.code} />
              </td>
              <th scope="row" className="px-3 py-2 text-left font-medium">
                {c.name}
                {c.etims ? <span className="block text-xs font-normal text-muted-foreground">KRA eTIMS type {c.code}</span> : null}
              </th>
              <td className="px-3 py-2">{c.kind}</td>
              <td className="px-3 py-2 text-right tabular-nums">
                {pct(c.rate)}
                <span className="block text-xs text-muted-foreground">since {formatDate(c.effectiveFrom)}</span>
                {c.next ? (
                  <span className="block text-xs font-medium text-status-info-text">
                    {pct(c.next.rate)} from {formatDate(c.next.from)}
                  </span>
                ) : null}
              </td>
              <td className="px-3 py-2 text-right tabular-nums">{c.products.toLocaleString("en-US")}</td>
              <td className="w-12 px-2 py-2 text-right">
                <RowActions label={`tax code ${c.code} ${c.name}`} actions={actionsFor(c)} />
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

/* ---------------------------------- Product review ---------------------------------- */

export type TaxProduct = { id: number; name: string; sub?: string; category: string; taxCode: string; /** Still on the code the migration gave it. */ reviewed: boolean };

/**
 * Product tax review (Phase 1.5 migration): every product starts on the old 16% as "Not reviewed". Filter,
 * tick several, assign a code; assigning marks them reviewed. "Keep 16%" confirms without changing.
 * The count of unreviewed products stays visible until it's zero.
 */
export function ProductTaxReview({ products, codes, onAssign }: { products: TaxProduct[]; codes: TaxCode[]; onAssign: (ids: number[], code: string) => void }) {
  const [query, setQuery] = React.useState("");
  const [category, setCategory] = React.useState("");
  const [onlyUnreviewed, setOnlyUnreviewed] = React.useState(true);
  const [selected, setSelected] = React.useState<Set<number>>(new Set());
  const [code, setCode] = React.useState(codes.find((c) => c.kind === "Exempt")?.code ?? codes[0].code);

  const categories = [...new Set(products.map((p) => p.category))].sort();
  const shown = products.filter((p) => (!onlyUnreviewed || !p.reviewed) && (!category || p.category === category) && (!query.trim() || p.name.toLowerCase().includes(query.trim().toLowerCase())));
  const left = products.filter((p) => !p.reviewed).length;
  const allOn = shown.length > 0 && shown.every((p) => selected.has(p.id));
  const toggle = (id: number) =>
    setSelected((s) => {
      const n = new Set(s);
      if (n.has(id)) n.delete(id);
      else n.add(id);
      return n;
    });
  const assign = (ids: number[], c: string) => {
    onAssign(ids, c);
    setSelected(new Set());
  };
  const codeOf = (c: string) => codes.find((x) => x.code === c);

  return (
    <div className="space-y-3">
      <p className={cn("flex items-start gap-2 rounded-md border px-3 py-2 text-sm", left ? TONE_BOX.warning : TONE_BOX.success)}>
        <InfoIcon className="mt-0.5 size-4 shrink-0" aria-hidden />
        {left
          ? `${left} of ${products.length} products are still on 16% VAT from before tax codes existed. Most medicines are exempt: review them before the next VAT return.`
          : "Every product has a reviewed tax code."}
      </p>
      <div className="flex flex-wrap items-center gap-2">
        <div className="relative w-full sm:w-56">
          <SearchIcon className="pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground" aria-hidden />
          <Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Find a product" aria-label="Find a product" className="pl-8" />
        </div>
        <NativeSelect aria-label="Category" value={category} onChange={(e) => setCategory(e.target.value)}>
          <NativeSelectOption value="">All categories</NativeSelectOption>
          {categories.map((c) => (
            <NativeSelectOption key={c} value={c}>
              {c}
            </NativeSelectOption>
          ))}
        </NativeSelect>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox checked={onlyUnreviewed} onCheckedChange={(v) => setOnlyUnreviewed(!!v)} /> Not reviewed only
        </label>
      </div>

      {/* Bulk bar: appears with a selection */}
      {selected.size ? (
        <div role="region" aria-label="Selected products" className="flex flex-wrap items-center gap-2 rounded-lg border border-[var(--color-border-strong)] bg-[var(--color-bg-selected)] px-3 py-2 text-sm">
          <span className="font-medium">{selected.size} selected</span>
          <NativeSelect size="sm" aria-label="Tax code to assign" value={code} onChange={(e) => setCode(e.target.value)} className="ml-auto">
            {codes.map((c) => (
              <NativeSelectOption key={c.code} value={c.code}>
                {c.code} · {c.name} ({pct(c.rate)})
              </NativeSelectOption>
            ))}
          </NativeSelect>
          <Button size="sm" onClick={() => assign([...selected], code)}>
            Assign {code}
          </Button>
          <Button size="sm" variant="ghost" onClick={() => setSelected(new Set())}>
            Clear
          </Button>
        </div>
      ) : null}

      <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
        <table className="w-full border-collapse text-sm">
          <caption className="sr-only">Products and their tax codes</caption>
          <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
            <tr>
              <th scope="col" className="w-10 px-3 py-2">
                <Checkbox
                  aria-label="Select all shown"
                  checked={allOn}
                  onCheckedChange={(v) => setSelected(v ? new Set([...selected, ...shown.map((p) => p.id)]) : new Set([...selected].filter((id) => !shown.some((p) => p.id === id))))}
                />
              </th>
              <th scope="col" className="px-3 py-2 font-medium">
                Product
              </th>
              <th scope="col" className="px-3 py-2 font-medium">
                Category
              </th>
              <th scope="col" className="px-3 py-2 font-medium">
                Tax code
              </th>
              <th scope="col" className="px-3 py-2">
                <span className="sr-only">Actions</span>
              </th>
            </tr>
          </thead>
          <tbody className="divide-y divide-[var(--color-border-subtle)]">
            {shown.length ? (
              shown.map((p) => {
                const c = codeOf(p.taxCode);
                return (
                  <tr key={p.id} className={cn(selected.has(p.id) && "bg-[var(--color-bg-selected)]")}>
                    <td className="px-3 py-2">
                      <Checkbox aria-label={`Select ${p.name}`} checked={selected.has(p.id)} onCheckedChange={() => toggle(p.id)} />
                    </td>
                    <th scope="row" className="px-3 py-2 text-left font-medium">
                      {p.name}
                      {p.sub ? <span className="block text-xs font-normal text-muted-foreground">{p.sub}</span> : null}
                    </th>
                    <td className="px-3 py-2 text-muted-foreground">{p.category}</td>
                    <td className="px-3 py-2">
                      <span className="inline-flex items-center gap-2">
                        <TaxBadge code={p.taxCode} />
                        <span className="whitespace-nowrap">{c ? `${c.name}, ${pct(c.rate)}` : p.taxCode}</span>
                        {!p.reviewed ? <span className="text-xs font-medium whitespace-nowrap text-status-warning-text">Not reviewed</span> : null}
                      </span>
                    </td>
                    <td className="px-3 py-2 text-right">
                      {!p.reviewed ? (
                        <Button size="xs" variant="ghost" onClick={() => assign([p.id], p.taxCode)}>
                          Keep {p.taxCode}
                        </Button>
                      ) : null}
                    </td>
                  </tr>
                );
              })
            ) : (
              <tr>
                <td colSpan={5} className="px-3 py-8 text-center text-sm text-muted-foreground">
                  {onlyUnreviewed && !left ? "Nothing left to review." : "No products match these filters."}
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* ------------------------------------ VAT by code ------------------------------------ */

export type TaxedLine = { id: string | number; name: string; qty: number; unitPrice: number; discount?: number; taxCode: string };

/** Taxable amount and VAT per code, VAT-exclusive prices, rounded to cents per code. */
export function vatByCode(lines: TaxedLine[], codes: TaxCode[]) {
  const map = new Map<string, { taxable: number; vat: number }>();
  for (const l of lines) {
    const net = l.qty * (l.unitPrice - (l.discount ?? 0));
    const rate = codes.find((c) => c.code === l.taxCode)?.rate ?? 0;
    const row = map.get(l.taxCode) ?? { taxable: 0, vat: 0 };
    row.taxable += net;
    row.vat += (net * rate) / 100;
    map.set(l.taxCode, row);
  }
  const rows = [...map.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([code, r]) => ({ code, taxable: Math.round(r.taxable * 100) / 100, vat: Math.round(r.vat * 100) / 100 }));
  const subtotal = rows.reduce((s, r) => s + r.taxable, 0);
  const vat = rows.reduce((s, r) => s + r.vat, 0);
  return { rows, subtotal, vat, total: Math.round((subtotal + vat) * 100) / 100 };
}

/** Breakdown under the cart and on receipts: one line per code used in the sale (PS-07). */
export function VatBreakdown({ lines, codes }: { lines: TaxedLine[]; codes: TaxCode[] }) {
  const t = vatByCode(lines, codes);
  const fmt = (n: number) => n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  return (
    <table className="w-full border-collapse text-sm tabular-nums">
      <caption className="sr-only">VAT by tax code</caption>
      <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
        <tr>
          <th scope="col" className="py-1 font-medium">
            Code
          </th>
          <th scope="col" className="py-1 text-right font-medium">
            Taxable
          </th>
          <th scope="col" className="py-1 text-right font-medium">
            VAT
          </th>
        </tr>
      </thead>
      <tbody>
        {t.rows.map((r) => {
          const c = codes.find((x) => x.code === r.code);
          return (
            <tr key={r.code} className="border-t border-[var(--color-border-subtle)]">
              <th scope="row" className="py-1 text-left font-normal">
                <span className="inline-flex items-center gap-1.5">
                  <TaxBadge code={r.code} /> {c ? `${c.name} ${pct(c.rate)}` : r.code}
                </span>
              </th>
              <td className="py-1 text-right">{fmt(r.taxable)}</td>
              <td className="py-1 text-right">{fmt(r.vat)}</td>
            </tr>
          );
        })}
      </tbody>
      <tfoot className="border-t-2 border-[var(--color-border-panel)] font-semibold">
        <tr>
          <th scope="row" className="py-1 text-left">
            Total KES
          </th>
          <td className="py-1 text-right">{fmt(t.subtotal)}</td>
          <td className="py-1 text-right">{fmt(t.vat)}</td>
        </tr>
        <tr>
          <th scope="row" colSpan={2} className="py-1 text-left">
            To pay
          </th>
          <td className="py-1 text-right text-base">{fmt(t.total)}</td>
        </tr>
      </tfoot>
    </table>
  );
}
