import autoTable from "jspdf-autotable";
import { formatIndianCurrency } from "@/utils/currency";
import { capitalizeFirst } from "@/utils/stringUtils";

export enum ChargeType {
  PERCENTAGE = "percentage",
  FIXED_AMOUNT = "fixedAmount",
  PER_SQ_FT = "perSqFt",
  PER_SQ_YARD = "perSqYard",
}

const chargeTypeFormatter: Record<ChargeType, (amount: string) => string> = {
  [ChargeType.PERCENTAGE]: (amount) => `${amount} %`,
  [ChargeType.FIXED_AMOUNT]: (amount) => `Rs. ${amount}`,
  [ChargeType.PER_SQ_FT]: (amount) => `Rs. ${amount} / sq.ft`,
  [ChargeType.PER_SQ_YARD]: (amount) => `Rs. ${amount} / sq.yd`,
};

/* ---------------- IMAGE HELPERS ---------------- */

const urlToBase64 = async (url: string): Promise<string | null> => {
  try {
    const res = await fetch(url, { mode: "cors" });
    const blob = await res.blob();

    return await new Promise((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result as string);
      reader.readAsDataURL(blob);
    });
  } catch {
    return null;
  }
};

const urlsToBase64 = async (urls: string[]) => {
  const results = await Promise.all(urls.map((url) => urlToBase64(url)));
  return results.filter(Boolean) as string[];
};

const detectImageType = (base64: string) => {
  if (base64.includes("image/png")) return "PNG";
  return "JPEG";
};

/* ---------------- IMAGE GRID ---------------- */

const renderImageGrid = (doc: any, images: string[], startY = 120) => {
  const imgWidth = 80;
  const imgHeight = 55;
  const startX = 20;
  const gapX = 4;
  const gapY = 4;

  images.forEach((img, index) => {
    const col = index % 2;
    const row = Math.floor(index / 2);
    const x = startX + col * (imgWidth + gapX);
    const y = startY + row * (imgHeight + gapY);
    doc.addImage(img, detectImageType(img), x, y, imgWidth, imgHeight);
  });
};

/* ---------------- AMENITIES GRID ---------------- */

const renderAmenities = (
  doc: any,
  amenities: { name: string; icon?: string }[],
  startY: number,
) => {
  doc.setFontSize(18);
  doc.setFont("helvetica", "bold");
  doc.text("4. Amenities", 20, startY);

  const colWidth = 42.5;
  const rowHeight = 28; 
  const iconSize = 12;

  amenities.forEach((amenity, index) => {
    const col = index % 4;
    const row = Math.floor(index / 4);

    const x = 20 + col * colWidth;
    const y = startY + 12 + row * rowHeight;

    doc.setDrawColor(220, 220, 220);
    doc.rect(x, y, colWidth, rowHeight);

    if (amenity.icon) {
      const iconX = x + (colWidth - iconSize) / 2;
      doc.addImage(
        amenity.icon,
        detectImageType(amenity.icon),
        iconX,
        y + 4,
        iconSize,
        iconSize,
      );
    }

    doc.setFontSize(8.5); // Smaller font size for a refined look
    doc.setFont("helvetica", "normal");
    doc.setTextColor(50, 50, 50); // Dark grey text for better readability

    const text = doc.splitTextToSize(amenity.name, colWidth - 4);

    // Position text closer to the icon for a unified "item" look
    doc.text(text, x + colWidth / 2, y + 22, { align: "center" });
  });
};

const renderRichText = (
  doc: any,
  textParts: { text: string; bold?: boolean }[],
  startX: number,
  startY: number,
  maxWidth: number,
) => {
  let x = startX;
  let y = startY;

  textParts.forEach((part) => {
    doc.setFont("helvetica", part.bold ? "bold" : "normal");
    const words = part.text.split(" ");
    words.forEach((word) => {
      const wordText = word + " ";
      const wordWidth = doc.getTextWidth(wordText);
      if (x + wordWidth > startX + maxWidth) {
        x = startX;
        y += 6;
      }
      doc.text(wordText, x, y);
      x += wordWidth;
    });
  });
  return y + 6;
};

/* ---------------- MAIN FUNCTION ---------------- */

export const generateQuotationPdf = async ({
  quotationNumber,
  companyName,
  assignedToName,
  assignedToPhone,
  assignedToEmail,
  leadName,
  projectName,
  unitNumber,
  unitType,
  unitSize,
  floor,
  parking,
  facing,
  finalAmount,
  comment,
  projectImage,
  makanifyLogo,
  mediaUrls = [],
  amenities = [],
  additionalCharges = [],
  companyLogo,
  location,
  reraId,
}: any) => {
  const { jsPDF } = await import("jspdf/dist/jspdf.umd.min.js");
  const doc = new jsPDF();

  const companyLogoBase64 = companyLogo ? await urlToBase64(companyLogo) : null;
  const projectImageBase64 = projectImage
    ? await urlToBase64(projectImage)
    : null;
  const makanifyLogoBase64 = makanifyLogo
    ? await urlToBase64(makanifyLogo)
    : null;
  const galleryImages = await urlsToBase64(mediaUrls);

  /* ---------- COVER PAGE ---------- */

  doc.setFont("helvetica", "bold");
  doc.setFontSize(28);
  doc.text(projectName || "Project", 105, 35, { align: "center" });

  doc.setFontSize(14);
  doc.setFont("helvetica", "normal");
  doc.text("Residential Project", 105, 45, { align: "center" });

  if (projectImageBase64) {
    doc.addImage(
      projectImageBase64,
      detectImageType(projectImageBase64),
      20,
      60,
      170,
      110,
    );
  }

  const footerY_Cover = 200;
  const logoWidth = 30;
  const logoHeight = 15;
  const gap = 6;
  doc.setFont("helvetica", "bold");
  doc.setFontSize(22);
  const companyText = companyName || "";
  const textWidth = doc.getTextWidth(companyText);
  const totalBlockWidth = logoWidth + gap + textWidth;
  const startX_Cover = (210 - totalBlockWidth) / 2;

  if (companyLogoBase64) {
    doc.addImage(
      companyLogoBase64,
      detectImageType(companyLogoBase64),
      startX_Cover,
      footerY_Cover - logoHeight / 2 + 2,
      logoWidth,
      logoHeight,
    );
    doc.text(companyText, startX_Cover + logoWidth + gap, footerY_Cover + 2);
  } else {
    doc.text(companyText, 105, footerY_Cover, { align: "center" });
  }

  /* ---------- INTRO PAGE ---------- */

  doc.addPage();
  let y = 30;
  doc.setFontSize(12);
  doc.text("To,", 20, y);
  y += 8;
  doc.text(leadName || "Client", 20, y);
  y += 12;

  y = renderRichText(
    doc,
    [
      { text: "Thank you for showing interest in our project " },
      { text: projectName, bold: true },
      {
        text: ". We are delighted to share a personalized quote with you. Experience the epitome of luxury and convenience in our ",
      },
      { text: projectName, bold: true },
      {
        text: " residences, where exceptional connectivity and superior quality living seamlessly merge. Experience the perfect blend of connectivity and quality living in our ",
      },
      { text: projectName, bold: true },
      {
        text: " residences. Elevate your lifestyle and relish a harmonious balance between modern connectivity and luxurious living like never before.",
      },
    ],
    20,
    y,
    170,
  );

  y += 15;
  doc.text("Best Regards,", 20, y);
  y += 6;
  doc.text(assignedToName || "-", 20, y);
  y += 6;
  doc.text(assignedToPhone || "-", 20, y);

  /* ---------- IMAGE GALLERY ---------- */

  if (galleryImages.length > 0) {
    let galleryStartY = y + 20;
    for (let i = 0; i < galleryImages.length; i += 4) {
      const chunk = galleryImages.slice(i, i + 4);
      if (i !== 0) {
        doc.addPage();
        galleryStartY = 40;
      }
      renderImageGrid(doc, chunk, galleryStartY);
    }
  }

  /* ---------- PROJECT DETAILS ---------- */

  doc.addPage();
  y = 30;
  doc.setFontSize(16);
  doc.setFont("helvetica", "bold");
  doc.text("1. Project Details", 20, y);

  const projectBody = [
    ["Project Name", projectName],
    ["Location", location],
    ["Developer", companyName],
    ["RERA ID", reraId],
  ].filter((row) => row[1] && row[1] !== ""); // Only show row if value exists

  autoTable(doc, {
    startY: y + 8,
    margin: { left: 20, right: 20 },
    theme: "grid",
    body: projectBody,
    styles: { fontSize: 11 },
    columnStyles: {
      0: { cellWidth: 60, fontStyle: "bold" },
      1: { cellWidth: 110 },
    },
  });

  y = (doc as any).lastAutoTable.finalY + 15;

  /* ---------- UNIT SPECIFICATIONS ---------- */

  doc.setFontSize(16);
  doc.setFont("helvetica", "bold");
  doc.text("2. Unit Specifications", 20, y);

  const unitBody = [
    ["Unit Number", unitNumber],
    ["Unit Type", unitType],
    ["Unit Size", unitSize ? `${unitSize} Sq. Yd.` : null],
    ["Floor", floor],
    ["Car Parking", parking],
    ["Facing Direction", facing],
    [
      "Final Amount",
      finalAmount
        ? formatIndianCurrency(finalAmount).replace("₹", "Rs. ")
        : null,
    ],
  ].filter((row) => row[1] && row[1] !== ""); // Only show row if value exists

  autoTable(doc, {
    startY: y + 8,
    theme: "grid",
    margin: { left: 20, right: 20 },
    body: unitBody,
    styles: { fontSize: 11 },
    columnStyles: {
      0: { cellWidth: 60, fontStyle: "bold" },
      1: { cellWidth: 110 },
    },
  });

  y = (doc as any).lastAutoTable.finalY + 20;

  /* ---------- ADDITIONAL CHARGES ---------- */

  if (additionalCharges.length > 0) {
    doc.setFont("helvetica", "bold");
    doc.setFontSize(16);
    doc.text("3. Additional Charges", 20, y);

    const chargesBody = additionalCharges.map((item: any) => {
      const amount = formatIndianCurrency(item.amount).replace(/[^\d,]/g, "");

      const formattedAmount =
        chargeTypeFormatter[item.chargeType as ChargeType]?.(amount) ?? amount;

      return [item.name, capitalizeFirst(item.chargeType), formattedAmount];
    });

    autoTable(doc, {
      startY: y + 8,
      theme: "grid",
      margin: { left: 20, right: 20 },
      head: [["Name", "Charge Type", "Amount (Rs)"]],
      body: chargesBody,
      styles: { fontSize: 11, cellPadding: 3 },
      headStyles: {
        fillColor: [240, 240, 240],
        textColor: [0, 0, 0],
        fontStyle: "bold",
      },
      columnStyles: {
        0: { cellWidth: 60, fontStyle: "bold" },
        1: { cellWidth: 70 },
        2: { cellWidth: 40 },
      },
    });

    y = (doc as any).lastAutoTable.finalY + 8;
    doc.setFont("helvetica", "italic");
    doc.setFontSize(10);
    doc.text(
      "* Base Price will vary as per project/builder and is not fixed in quotation.",
      20,
      y,
    );
    y += 15;
  }

  /* ---------- NOTES ---------- */

  if (comment && comment.trim() !== "" && comment !== "-") {
    doc.setFontSize(14);
    doc.setFont("helvetica", "bold");
    doc.text("Additional Notes", 20, y);
    y += 10;
    doc.setFontSize(11);
    doc.setFont("helvetica", "normal");
    const splitComment = doc.splitTextToSize(comment, 170);
    doc.text(splitComment, 20, y);
    y += splitComment.length * 6 + 15;
  }

  /* ---------- AMENITIES ---------- */

  if (amenities.length > 0) {
    doc.addPage();
    renderAmenities(doc, amenities, 30);
  }

  /* ---------- CONTACT PAGE ---------- */

  doc.addPage();
  let contactY = 80;
  doc.setFontSize(14);
  doc.setFont("helvetica", "normal");
  doc.setTextColor(100, 100, 100);
  doc.text("Get In Touch", 105, contactY, { align: "center" });

  contactY += 25;
  doc.setFontSize(20);
  doc.setFont("helvetica", "bold");
  doc.setTextColor(0, 0, 0);

  const cName = companyName || "";
  const cTextWidth = doc.getTextWidth(cName);
  const cLogoW = 35;
  const cLogoH = 18;
  const cGap = 8;
  const cStartX = (210 - (cLogoW + cGap + cTextWidth)) / 2;

  if (companyLogoBase64) {
    doc.addImage(
      companyLogoBase64,
      detectImageType(companyLogoBase64),
      cStartX,
      contactY - cLogoH / 2 + 2,
      cLogoW,
      cLogoH,
    );
    doc.text(cName, cStartX + cLogoW + cGap, contactY + 3);
  } else {
    doc.text(cName, 105, contactY, { align: "center" });
  }

  contactY += 25;
  doc.setFontSize(12);
  doc.setFont("helvetica", "normal");
  doc.setTextColor(100, 100, 100);
  doc.text(`Phone: ${assignedToPhone || "-"}`, 105, contactY, {
    align: "center",
  });
  contactY += 10;
  doc.text(`Email: ${assignedToEmail || "-"}`, 105, contactY, {
    align: "center",
  });

  // Powered by
  const finalFooterY = 260;
  doc.setFontSize(10);
  doc.text("Powered by", 105, finalFooterY, { align: "center" });
  if (makanifyLogoBase64) {
    const mWidth = 45;
    const mHeight = 10;
    doc.addImage(
      makanifyLogoBase64,
      detectImageType(makanifyLogoBase64),
      105 - mWidth / 2,
      finalFooterY + 4,
      mWidth,
      mHeight,
    );
  }

  /* ---------- OUTPUT ---------- */

  const blob = doc.output("blob");
  return new File([blob], `quotation-${quotationNumber}.pdf`, {
    type: "application/pdf",
  });
};
