"use client";

/**
 * The receipt after a sale and on a reprint, on the design's thermal receipt (`Receipt`, card 015): built from the sale
 * as the API stored it (lines with their tax codes and rates, every tender, delivery), with the pharmacy's details and
 * receipt settings (ST-16). A sale not sent to eTIMS carries no VAT and prints none. The eTIMS block is left out until
 * sales are actually sent to KRA (IG-09); printing "queued" or a signature would claim something that hasn't happened.
 */

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

import { Receipt, type CartItem, type ReceiptData } from "@/components/medora/sale";
import { DocumentSheet, PrintButton, VAT_CLASS, printElement, type DocLine, type VatClass } from "@/components/medora/print";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import type { RxFromSale } from "../prescriptions/prescription-form";

export type StoredSale = {
  id: number;
  receiptId: string;
  createdAt: string;
  total: number | string;
  tax: number | string;
  isEtims: boolean;
  isCredit?: boolean;
  preorderId?: number | null;
  amountPaid?: number | string;
  paymentMethod: string;
  customerId?: number | null;
  customerName?: string | null;
  cashier?: { name?: string; username?: string } | null;
  branchId?: number | null;
  items: { productId: number; product?: { name?: string } | null; quantity: number; unitPrice: number | string; discount?: number | string | null; taxCode?: string | null; taxRate?: number | string | null }[];
  payments?: { method: "Cash" | "M-Pesa" | "Card"; amount: number | string; reference?: string | null; tendered?: number | string | null }[];
  isDelivery?: boolean;
  deliveryFee?: number | string | null;
  deliveryAddress?: string | null;
  deliveryLocality?: string | null;
  riderName?: string | null;
  riderPhone?: string | null;
  // Plan E
  courierCompany?: string | null;
  deliveryPickup?: string | null;
  discountSource?: string | null;
  promotions?: { name: string; amount: number | string }[];
};

const n = (v: unknown) => Number(v) || 0;
const pad = (x: number) => String(x).padStart(2, "0");
/** "YYYY-MM-DDTHH:MM" in local time, as the receipt's reprint line reads it. */
const localStamp = (d: Date) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;

/** The design's receipt data from a stored sale. */
export function receiptData(sale: StoredSale, ctx: { branch: string; settings: Record<string, string>; taxNames: Record<string, string>; reprintBy?: string }): ReceiptData {
  const at = new Date(sale.createdAt);
  const s = (k: string) => ctx.settings[k] || "";
  const items: CartItem[] = sale.items.map((i, k) => ({
    id: i.productId * 1000 + k,
    name: i.product?.name ?? `Product #${i.productId}`,
    unitPrice: n(i.unitPrice),
    qty: i.quantity,
    discount: n(i.discount),
    taxCode: (i.taxCode ?? "B") as CartItem["taxCode"],
  }));
  // Rates as stored on the sale's lines; delivery is taxed at B, 16% (sale-money.ts)
  const rates = new Map<string, number>();
  sale.items.forEach((i) => rates.set(i.taxCode ?? "B", i.taxRate == null ? 16 : n(i.taxRate)));
  if (n(sale.deliveryFee) && !rates.has("B")) rates.set("B", 16);
  const paid = (sale.payments ?? []).map((p) => ({ method: p.method, amount: n(p.amount), reference: p.reference ?? undefined, tendered: p.tendered == null ? undefined : n(p.tendered) }));
  const credit = sale.isCredit ? Math.max(0, Math.round((n(sale.total) - paid.reduce((t, p) => t + p.amount, 0)) * 100) / 100) : 0;
  return {
    receiptNo: sale.receiptId,
    date: `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`,
    time: `${pad(at.getHours())}:${pad(at.getMinutes())}`,
    cashier: sale.cashier?.name || sale.cashier?.username || "",
    branch: ctx.branch,
    items,
    deliveryFee: n(sale.deliveryFee) || undefined,
    method: (["Cash", "M-Pesa", "Card", "Credit"].includes(sale.paymentMethod) ? sale.paymentMethod : "Cash") as ReceiptData["method"],
    payments: paid,
    credit: credit || undefined,
    // PS-14: collecting a preorder puts its deposit, already paid, against the sale; it isn't owed
    creditLabel: sale.preorderId ? "Deposit paid earlier" : undefined,
    vatApplies: sale.isEtims,
    taxCodes: [...rates].map(([code, rate]) => ({ code, name: ctx.taxNames[code] ?? code, rate })),
    deliveryTaxCode: "B",
    etimsBlock: false,
    customer: sale.customerName || undefined,
    delivery: sale.isDelivery
      ? { locality: sale.deliveryLocality ?? undefined, address: sale.deliveryAddress ?? undefined, rider: sale.riderName ?? undefined, riderPhone: sale.riderPhone ?? undefined, courier: sale.courierCompany ?? undefined, pickup: sale.deliveryPickup ?? undefined }
      : undefined,
    // Plan E (Q2): which discount applied
    promotions: sale.promotions?.length ? sale.promotions.map((p) => ({ name: p.name, amount: n(p.amount) })) : undefined,
    discountNote: sale.discountSource === "Manual" && sale.items.some((i) => n(i.discount) > 0) ? "Discount given by the cashier; promotions don't apply with it." : sale.discountSource === "Group" ? "Customer group prices." : undefined,
    reprint: ctx.reprintBy ? { at: localStamp(new Date()), by: ctx.reprintBy } : undefined,
    hideCashier: s("receipt_show_cashier") === "false",
    issuer: {
      name: s("store_name") || "Pharmacy",
      tagline: s("store_tagline") || undefined,
      address: s("receipt_show_address") === "true" ? s("store_address") || undefined : undefined,
      phone: s("store_phone") || undefined,
      email: s("store_email") || undefined,
      title: s("receipt_title") || undefined,
      header: s("receipt_header") || undefined,
      footer: s("receipt_footer") || "Thank you for your purchase!",
    },
  };
}

/** What the old prescription and return screens still take (legacy.tsx). */
/** A completed sale, for writing its prescription at the till (the shared prescription form). */
export function rxFromSale(sale: StoredSale): RxFromSale {
  return {
    saleId: sale.id,
    receiptId: sale.receiptId,
    customer: sale.customerName ? { id: sale.customerId ?? undefined, name: sale.customerName } : null,
    items: sale.items.map((i) => ({ id: i.productId, name: i.product?.name ?? `Product #${i.productId}`, qty: i.quantity })),
  };
}

export function TillReceiptDialog({
  data,
  title,
  autoPrint,
  onDone,
  doneLabel,
  onGenerateRx,
}: {
  data: ReceiptData;
  title: string;
  autoPrint?: boolean;
  onDone: () => void;
  doneLabel: string;
  onGenerateRx?: () => void;
}) {
  const ref = React.useRef<HTMLDivElement>(null);
  React.useEffect(() => {
    if (!autoPrint) return;
    const t = setTimeout(() => ref.current && printElement(ref.current, "receipt-80"), 300);
    return () => clearTimeout(t);
  }, [autoPrint]);
  return (
    <Dialog open onOpenChange={(o) => !o && onDone()}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>Receipt {data.receiptNo}</DialogDescription>
        </DialogHeader>
        <div className="max-h-[60svh] overflow-auto rounded-md bg-muted/40 p-3">
          <Receipt ref={ref} data={data} />
        </div>
        <DialogFooter className="flex-wrap gap-2 sm:justify-between">
          {onGenerateRx ? (
            <Button variant="ghost" onClick={onGenerateRx}>
              <FileTextIcon data-icon="inline-start" />
              Generate prescription
            </Button>
          ) : (
            <span />
          )}
          <div className="flex gap-2">
            <PrintButton target={ref} paper="receipt-80" label="Print" />
            <Button onClick={onDone}>{doneLabel}</Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

/**
 * A quotation for the basket on the design's A4 document (PS-09). Quotations aren't stored, as before: the number is
 * made when it's printed. On a sale that won't be sent to eTIMS the lines are Non-VAT (D), matching what the till
 * would charge; otherwise each line carries its product's tax code.
 */
export function QuotationDialog({
  reference,
  validUntil,
  lines,
  etims,
  customer,
  branch,
  settings,
  printedBy,
  onClose,
}: {
  /** The saved quotation's number (QUO-…, plan H AC-15). */
  reference: string;
  validUntil?: string;
  lines: { code: string; name: string; unit?: string; qty: number; price: number; discount: number; taxCode?: string }[];
  etims: boolean;
  customer: string | null;
  branch: string;
  settings: Record<string, string>;
  printedBy: string;
  onClose: () => void;
}) {
  const ref = React.useRef<HTMLDivElement>(null);
  const now = new Date();
  const docLines: DocLine[] = lines.map((l) => ({
    code: l.code,
    name: l.name,
    unit: l.unit || undefined,
    qty: l.qty,
    price: l.price,
    discount: l.discount || undefined,
    vat: (etims ? (l.taxCode && l.taxCode in VAT_CLASS ? l.taxCode : "B") : "D") as VatClass,
  }));
  return (
    <Dialog open onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="sm:max-w-4xl">
        <DialogHeader>
          <DialogTitle>Quotation</DialogTitle>
          <DialogDescription>Saved as {reference}{validUntil ? `, valid until ${validUntil}` : ""}. It can be sold at the till or invoiced from Accounts → Receivables.</DialogDescription>
        </DialogHeader>
        <div className="max-h-[65svh] overflow-auto rounded-md bg-muted/40 p-3">
          <DocumentSheet
            ref={ref}
            kind="quotation"
            issuer={{ name: settings.store_name || "Pharmacy", branch, address: settings.store_address ? [settings.store_address] : [], phone: settings.store_phone || undefined, email: settings.store_email || undefined }}
            party={{ name: customer || "Walk-in customer" }}
            reference={reference}
            validUntil={validUntil}
            date={`${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`}
            lines={docLines}
            printedBy={printedBy}
            printedAt={localStamp(now)}
          />
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={onClose}>
            Close
          </Button>
          <PrintButton target={ref} paper="a4" label="Print quotation" variant="default" />
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
