import { jsPDF } from "jspdf";
import { COMPANY } from "./company";
import { formatDate, formatMoney } from "./locale";

const BRAND: [number, number, number] = [16, 94, 66];
const INK: [number, number, number] = [28, 32, 36];
const MUTED: [number, number, number] = [110, 118, 126];
const LINE: [number, number, number] = [222, 227, 231];
const M = 14;

export type BillingItem = { description: string; quantity: number; unit_price: number };

export type BillingDoc = {
  kind: "Quotation" | "Invoice";
  reference: string;
  issuedAt: string | Date;
  validUntil?: string | null;
  dueDate?: string | null;
  status: string;
  country?: string | null;
  provider: {
    name: string;
    email?: string | null;
    phone?: string | null;
    address?: string | null;
    logoDataUrl?: string | null;
  };
  customer: {
    name?: string | null;
    email?: string | null;
    phone?: string | null;
    address?: string | null;
  };
  items: BillingItem[];
  subtotal: number;
  discount: number;
  vatRate: number;
  vatAmount: number;
  total: number;
  bank?: { bank?: string | null; accountName?: string | null; accountNumber?: string | null } | null;
  notes?: string | null;
};

export async function buildBillingPdf(input: BillingDoc): Promise<Blob> {
  const doc = new jsPDF({ unit: "mm", format: "a4", compress: true });
  const w = doc.internal.pageSize.getWidth();
  const h = doc.internal.pageSize.getHeight();
  const cw = w - M * 2;
  const cc = input.country;
  let y = M;

  // Header band
  doc.setFillColor(...BRAND);
  doc.rect(0, 0, w, 30, "F");
  if (input.provider.logoDataUrl) {
    try {
      doc.addImage(input.provider.logoDataUrl, "PNG", M, 6, 18, 18);
    } catch {
      /* logo optional */
    }
  }
  doc.setTextColor(255, 255, 255);
  doc.setFont("helvetica", "bold");
  doc.setFontSize(14);
  doc.text(input.provider.name, M + (input.provider.logoDataUrl ? 22 : 0), 14);
  doc.setFont("helvetica", "normal");
  doc.setFontSize(8.5);
  const contact = [input.provider.email, input.provider.phone, input.provider.address].filter(Boolean).join(" · ");
  doc.text(contact || COMPANY.tagline, M + (input.provider.logoDataUrl ? 22 : 0), 20);
  doc.setFont("helvetica", "bold");
  doc.setFontSize(16);
  doc.text(input.kind.toUpperCase(), w - M, 15, { align: "right" });
  doc.setFont("helvetica", "normal");
  doc.setFontSize(9);
  doc.text(input.reference, w - M, 21, { align: "right" });
  y = 40;

  // Parties
  const half = cw / 2 - 3;
  const block = (x: number, title: string, lines: (string | null | undefined)[]) => {
    doc.setFont("helvetica", "bold");
    doc.setFontSize(8.5);
    doc.setTextColor(...BRAND);
    doc.text(title.toUpperCase(), x, y);
    doc.setFont("helvetica", "normal");
    doc.setFontSize(9.5);
    doc.setTextColor(...INK);
    let ly = y + 5;
    lines.filter(Boolean).forEach((line) => {
      const wrapped = doc.splitTextToSize(String(line), half) as string[];
      wrapped.forEach((t) => {
        doc.text(t, x, ly);
        ly += 4.4;
      });
    });
    return ly;
  };
  const leftEnd = block(M, "Billed to", [
    input.customer.name ?? "Not provided",
    input.customer.address,
    input.customer.email,
    input.customer.phone,
  ]);
  const rightEnd = block(M + half + 6, `${input.kind} details`, [
    `Issued: ${formatDate(input.issuedAt, cc)}`,
    input.validUntil ? `Valid until: ${formatDate(input.validUntil, cc)}` : null,
    input.dueDate ? `Payment due: ${formatDate(input.dueDate, cc)}` : null,
    `Status: ${input.status}`,
  ]);
  y = Math.max(leftEnd, rightEnd) + 6;

  // Items table
  doc.setFillColor(...BRAND);
  doc.roundedRect(M, y, cw, 8, 1.5, 1.5, "F");
  doc.setFont("helvetica", "bold");
  doc.setFontSize(9);
  doc.setTextColor(255, 255, 255);
  doc.text("Description", M + 2, y + 5.4);
  doc.text("Qty", M + cw * 0.58, y + 5.4, { align: "right" });
  doc.text("Unit price", M + cw * 0.78, y + 5.4, { align: "right" });
  doc.text("Amount", w - M - 2, y + 5.4, { align: "right" });
  y += 11;

  doc.setFont("helvetica", "normal");
  doc.setFontSize(9.5);
  for (const item of input.items) {
    const amount = Number(item.quantity || 0) * Number(item.unit_price || 0);
    const wrapped = doc.splitTextToSize(item.description || "—", cw * 0.55) as string[];
    if (y + wrapped.length * 4.4 > h - 60) {
      doc.addPage();
      y = M + 6;
    }
    doc.setTextColor(...INK);
    wrapped.forEach((t, i) => doc.text(t, M + 2, y + i * 4.4));
    doc.text(String(item.quantity), M + cw * 0.58, y, { align: "right" });
    doc.text(formatMoney(Number(item.unit_price || 0), cc), M + cw * 0.78, y, { align: "right" });
    doc.setFont("helvetica", "bold");
    doc.text(formatMoney(amount, cc), w - M - 2, y, { align: "right" });
    doc.setFont("helvetica", "normal");
    y += Math.max(1, wrapped.length) * 4.4 + 2;
    doc.setDrawColor(...LINE);
    doc.line(M, y - 1.4, w - M, y - 1.4);
  }

  // Totals
  y += 4;
  const totalRow = (label: string, value: string, bold = false) => {
    doc.setFont("helvetica", bold ? "bold" : "normal");
    doc.setFontSize(bold ? 11 : 9.5);
    doc.setTextColor(...(bold ? INK : MUTED));
    doc.text(label, w - M - 46, y, { align: "right" });
    doc.setTextColor(...INK);
    doc.setFont("helvetica", "bold");
    doc.text(value, w - M - 2, y, { align: "right" });
    y += bold ? 8 : 5.6;
  };
  totalRow("Subtotal", formatMoney(input.subtotal, cc));
  if (input.discount) totalRow("Discount", `- ${formatMoney(input.discount, cc)}`);
  totalRow(`VAT (${input.vatRate}%)`, formatMoney(input.vatAmount, cc));
  doc.setDrawColor(...LINE);
  doc.line(w - M - 60, y - 3, w - M, y - 3);
  y += 2;
  totalRow("Total due", formatMoney(input.total, cc), true);

  // Bank details
  if (input.bank?.accountNumber) {
    y += 2;
    doc.setFillColor(245, 248, 246);
    doc.roundedRect(M, y, cw, 22, 2, 2, "F");
    doc.setFont("helvetica", "bold");
    doc.setFontSize(9);
    doc.setTextColor(...BRAND);
    doc.text("PAYMENT DETAILS", M + 3, y + 6);
    doc.setFont("helvetica", "normal");
    doc.setTextColor(...INK);
    doc.setFontSize(9.5);
    doc.text(`Bank: ${input.bank.bank ?? "—"}`, M + 3, y + 12);
    doc.text(`Account name: ${input.bank.accountName ?? "—"}`, M + 3, y + 17);
    doc.text(`Account number: ${input.bank.accountNumber}`, M + cw / 2, y + 17);
    y += 26;
  }

  if (input.notes) {
    doc.setFont("helvetica", "normal");
    doc.setFontSize(9);
    doc.setTextColor(...MUTED);
    const wrapped = doc.splitTextToSize(input.notes, cw) as string[];
    wrapped.forEach((t) => {
      doc.text(t, M, y);
      y += 4.2;
    });
  }

  // Footer
  const pages = doc.getNumberOfPages();
  for (let p = 1; p <= pages; p += 1) {
    doc.setPage(p);
    doc.setFont("helvetica", "normal");
    doc.setFontSize(7.6);
    doc.setTextColor(...MUTED);
    doc.text(`${input.provider.name} · ${COMPANY.website}`, M, h - 8);
    doc.text(`Page ${p} of ${pages}`, w - M, h - 8, { align: "right" });
  }

  return doc.output("blob");
}