import jsPDF from "jspdf";
import autoTable from "jspdf-autotable";
import { splitMailingAddressLines } from "@/lib/ownerAddressUtils";

interface InvoiceItem {
  description: string;
  amount: number;
  /** Property address attributed to this charge */
  address?: string;
  /** Vendor name attributed to this charge */
  vendor?: string;
}

interface HomeownerInvoiceData {
  invoiceNumber: string;
  invoiceDate: string;
  dueDate: string;
  billingPeriod?: string;
  associationName: string;
  associationCareOf?: string;
  associationMailingAddress?: string;
  companyName?: string;
  companyAddress?: string;
  ownerName: string;
  ownerAddress: string;
  ownerMailingAddress?: string;
  ownerCity?: string;
  ownerState?: string;
  ownerZip?: string;
  accountNumber?: string;
  items: InvoiceItem[];
  notes?: string;
  logoUrl?: string | null;
  /** When true, use company name/address as sender header; otherwise use association */
  useCompanyAsSender?: boolean;
}

const fmtCurrency = (v: number) =>
  new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(v);

async function fetchLogoAsDataUrl(url: string): Promise<string | null> {
  try {
    const response = await fetch(url, { mode: "cors" });
    if (!response.ok) return null;
    const blob = await response.blob();
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result as string);
      reader.onerror = () => resolve(null);
      reader.readAsDataURL(blob);
    });
  } catch {
    return null;
  }
}

export async function generateHomeownerInvoicePdf(data: HomeownerInvoiceData) {
  const doc = new jsPDF();
  const pw = doc.internal.pageSize.getWidth();
  const ph = doc.internal.pageSize.getHeight();

  // ── Load logo ──
  let logoDataUrl: string | null = null;
  if (data.logoUrl) {
    logoDataUrl = await fetchLogoAsDataUrl(data.logoUrl);
  }

  // ── Sender header (top-left) — defaults to association, toggle for company ──
  doc.setFontSize(10);
  doc.setFont("helvetica", "normal");
  doc.setTextColor(80, 80, 80);
  let headerY = 22;

  if (data.useCompanyAsSender) {
    // Company as sender
    doc.text(data.companyName || "Avria Community Management", 14, headerY);
    if (data.companyAddress) {
      const lines = data.companyAddress.split("\n");
      lines.forEach((line: string) => {
        headerY += 5;
        doc.text(line, 14, headerY);
      });
    }
  } else {
    // Association as sender (default)
    doc.text(data.associationName || "", 14, headerY);
    const assocAddrParts: string[] = [];
    if (data.associationCareOf) assocAddrParts.push(`C/O ${data.associationCareOf}`);
    // Split mailing address into separate lines (Address / City, State Zip)
    const mailingLines = splitMailingAddressLines(data.associationMailingAddress);
    mailingLines.forEach((line) => assocAddrParts.push(line));
    assocAddrParts.forEach((line) => {
      headerY += 5;
      doc.text(line, 14, headerY);
    });
  }

  // ── Logo (top-right, above INVOICE) ──
  if (logoDataUrl) {
    try {
      doc.addImage(logoDataUrl, "PNG", pw - 14 - 40, 10, 40, 14);
    } catch {
      // silently skip if image fails
    }
  }

  // ── "INVOICE" label (top-right) ──
  doc.setFontSize(24);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(30, 30, 30);
  doc.text("INVOICE", pw - 14, logoDataUrl ? 36 : 28, { align: "right" });

  // ── Association name ──
  let y = headerY + 16;
  doc.setFontSize(13);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(30, 30, 30);
  doc.text(data.associationName, 14, y);

  // ── Bill To & Invoice Meta ──
  y += 14;
  doc.setFontSize(10);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(30, 30, 30);
  doc.text("BILL TO:", 14, y);

  // Invoice meta (right side)
  const metaX = pw - 14;
  const metaLabelX = pw - 80;
  let metaY = y;
  doc.setFontSize(10);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(60, 60, 60);

  const metaItems: [string, string][] = [
    ["Invoice #:", data.invoiceNumber],
    ["Date:", data.invoiceDate],
    ["Due Date:", data.dueDate || "Upon Receipt"],
  ];
  if (data.billingPeriod) metaItems.push(["Billing Period:", data.billingPeriod]);
  if (data.accountNumber) metaItems.push(["Account #:", data.accountNumber]);

  metaItems.forEach(([label, value]) => {
    doc.setFont("helvetica", "bold");
    doc.text(label, metaLabelX, metaY);
    doc.setFont("helvetica", "normal");
    doc.text(value, metaX, metaY, { align: "right" });
    metaY += 6;
  });

  // Owner address (prefer mailing address over property address for BILL TO)
  y += 6;
  doc.setFont("helvetica", "normal");
  doc.setTextColor(50, 50, 50);
  doc.text(data.ownerName, 14, y);
  y += 5;
  const billToAddr = data.ownerMailingAddress || data.ownerAddress;
  if (billToAddr) { doc.text(billToAddr, 14, y); y += 5; }
  const ownerCityLine = [data.ownerCity, data.ownerState, data.ownerZip].filter(Boolean).join(", ");
  if (ownerCityLine) { doc.text(ownerCityLine, 14, y); y += 5; }

  // ── Items Table ──
  const tableY = Math.max(y, metaY) + 14;
  const total = data.items.reduce((s, i) => s + i.amount, 0);

  // Track which body rows have annotations
  const annotationRows = new Map<number, string>();
  const tableBody = data.items.map((item, idx) => {
    const annotations: string[] = [];
    if (item.address) annotations.push(item.address);
    if (item.vendor) annotations.push(item.vendor);
    if (annotations.length > 0) {
      annotationRows.set(idx, annotations.join(" • "));
    }
    return [item.description, fmtCurrency(item.amount)];
  });

  // Total row
  tableBody.push(["TOTAL DUE", fmtCurrency(total)]);

  autoTable(doc, {
    startY: tableY,
    head: [["Description", "Amount"]],
    body: tableBody,
    theme: "grid",
    headStyles: {
      fillColor: [35, 45, 55],
      textColor: [255, 255, 255],
      fontStyle: "bold",
      fontSize: 10,
    },
    bodyStyles: {
      fontSize: 10,
      textColor: [40, 40, 40],
    },
    columnStyles: {
      0: { cellWidth: pw - 28 - 40 },
      1: { halign: "right" as const, cellWidth: 40 },
    },
    margin: { left: 14, right: 14 },
    didParseCell: (hookData: any) => {
      const rowIdx = hookData.row.index;
      if (hookData.section === "body" && rowIdx === tableBody.length - 1) {
        hookData.cell.styles.fontStyle = "bold";
        hookData.cell.styles.fillColor = [245, 245, 245];
      }
      // Add extra padding for annotation rows
      if (hookData.section === "body" && annotationRows.has(rowIdx)) {
        hookData.cell.styles.cellPadding = { top: 4, bottom: 12, left: 5, right: 5 };
      }
    },
    didDrawCell: (hookData: any) => {
      if (hookData.section === "body" && hookData.column.index === 0) {
        const annotation = annotationRows.get(hookData.row.index);
        if (annotation) {
          doc.setFontSize(7);
          doc.setFont("helvetica", "italic");
          doc.setTextColor(120, 120, 120);
          doc.text(annotation, hookData.cell.x + 6, hookData.cell.y + hookData.cell.height - 3);
        }
      }
    },
  });

  // ── Notes ──
  const finalY = (doc as any).lastAutoTable?.finalY || tableY + 60;
  if (data.notes) {
    let noteY = finalY + 14;
    doc.setFontSize(10);
    doc.setFont("helvetica", "bold");
    doc.setTextColor(30, 30, 30);
    doc.text("Notes:", 14, noteY);
    noteY += 6;
    doc.setFont("helvetica", "normal");
    doc.setTextColor(60, 60, 60);
    doc.text(data.notes, 14, noteY);
  }

  // ── Remittance Slip ──
  const slipY = ph - 100;

  // Dashed line
  doc.setDrawColor(150, 150, 150);
  doc.setLineDashPattern([4, 3], 0);
  doc.setLineWidth(0.5);
  doc.line(14, slipY, pw - 14, slipY);
  doc.setLineDashPattern([], 0);

  // Label
  doc.setFontSize(8);
  doc.setTextColor(120, 120, 120);
  doc.text("DETACH AND RETURN THIS PORTION WITH PAYMENT", pw / 2, slipY + 5, { align: "center" });

  // Slip content
  let slipContentY = slipY + 14;
  doc.setFontSize(10);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(30, 30, 30);
  doc.text(data.associationName, 14, slipContentY);

  slipContentY += 6;
  doc.setFont("helvetica", "normal");
  doc.setTextColor(60, 60, 60);
  doc.setFontSize(9);
  if (data.accountNumber) doc.text(`Account: ${data.accountNumber}`, 14, slipContentY);
  slipContentY += 5;
  doc.text(`Invoice: ${data.invoiceNumber}`, 14, slipContentY);
  slipContentY += 8;
  doc.text(data.ownerName, 14, slipContentY);
  slipContentY += 5;
  const remitAddr = data.ownerMailingAddress || data.ownerAddress;
  if (remitAddr) doc.text(remitAddr, 14, slipContentY);
  slipContentY += 5;
  if (ownerCityLine) doc.text(ownerCityLine, 14, slipContentY);

  // Total box (right side of slip)
  const boxX = pw - 100;
  const boxY = slipY + 12;
  doc.setDrawColor(0, 0, 0);
  doc.setLineWidth(0.5);
  doc.rect(boxX, boxY, 86, 30);

  doc.setFontSize(10);
  doc.setFont("helvetica", "normal");
  doc.setTextColor(30, 30, 30);
  doc.text("Total Due:", boxX + 4, boxY + 10);
  doc.setFont("helvetica", "bold");
  doc.text(fmtCurrency(total), boxX + 82, boxY + 10, { align: "right" });

  doc.setFont("helvetica", "normal");
  doc.text("Amount Enclosed:", boxX + 4, boxY + 22);
  doc.setDrawColor(0, 0, 0);
  doc.setLineWidth(0.3);
  doc.line(boxX + 50, boxY + 24, boxX + 82, boxY + 24);

  // Make Check Payable To
  const payY = slipContentY + 12;
  doc.setFontSize(9);
  doc.setFont("helvetica", "normal");
  doc.setTextColor(40, 40, 40);
  doc.text("Make Check Payable To:", 14, payY);
  doc.setFont("helvetica", "bold");
  doc.text(data.associationName, 60, payY);

  doc.setFont("helvetica", "normal");
  doc.text("Mail Payment To:", 14, payY + 6);
  doc.setFont("helvetica", "bold");
  const mailTo = data.associationCareOf || data.companyAddress || "";
  if (mailTo) {
    const mailLines = mailTo.split("\n");
    let mailY = payY + 6;
    mailLines.forEach((line: string) => {
      doc.text(line, 60, mailY);
      mailY += 5;
    });
  }

  // ── Scan line (account encoding) ──
  if (data.accountNumber) {
    doc.setFontSize(10);
    doc.setFont("courier", "normal");
    doc.setTextColor(60, 60, 60);
    const scanCode = `000${data.accountNumber.replace(/\D/g, "").padStart(6, "0")}000   ${String(Math.round(total * 100)).padStart(5, "0")}   00`;
    doc.text(scanCode, 14, ph - 10);
  }

  // ── Save ──
  doc.save(`Invoice_${data.invoiceNumber}_${data.ownerName.replace(/\s+/g, "_")}.pdf`);
}
