import { PDFDocument, PDFPage, StandardFonts, rgb } from "pdf-lib";
import { PdfCustomerAddress } from "@/lib/customer-address";
import { legalInfo } from "@/lib/legal";
import { getQuoteExpirationDate, type CustomerQuote } from "@/lib/medusa/quotes";
import type { QuoteSettingsContent } from "@/lib/sanity/queries";

type QuotePdfData = {
  quote: CustomerQuote;
  customerAddress?: PdfCustomerAddress | null;
  settings: QuoteSettingsContent | null;
};

function formatDate(value?: string | Date | null) {
  if (!value) return "-";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "-";
  return new Intl.DateTimeFormat("fr-FR", { dateStyle: "medium" }).format(date);
}

function formatCurrency(amount?: number | null, currencyCode?: string | null) {
  if (typeof amount !== "number") {
    return "-";
  }
  const currency = (currencyCode || "eur").toUpperCase();
  return new Intl.NumberFormat("fr-FR", {
    style: "currency",
    currency,
  }).format(amount / 100);
}

function parseHexColor(hex?: string) {
  const fallback = rgb(0.96, 0.31, 0.31);
  if (!hex) return fallback;
  const normalized = hex.replace("#", "").trim();
  if (!/^[0-9a-fA-F]{6}$/.test(normalized)) return fallback;
  const r = parseInt(normalized.slice(0, 2), 16) / 255;
  const g = parseInt(normalized.slice(2, 4), 16) / 255;
  const b = parseInt(normalized.slice(4, 6), 16) / 255;
  return rgb(r, g, b);
}

function toLines(value?: string | null) {
  return String(value || "")
    .split(/\r?\n/g)
    .map((line) => line.trim())
    .filter(Boolean);
}

function drawTextLines(
  page: PDFPage,
  lines: string[],
  options: {
    x: number;
    y: number;
    size: number;
    font: Awaited<ReturnType<PDFDocument["embedFont"]>>;
    color?: ReturnType<typeof rgb>;
    lineGap?: number;
  },
) {
  const { x, y, size, font, color, lineGap = 4 } = options;
  let currentY = y;
  for (const line of lines) {
    page.drawText(line, { x, y: currentY, size, font, color });
    currentY -= size + lineGap;
  }
  return currentY;
}

function withSanityPngFormat(url: string) {
  try {
    const parsed = new URL(url);
    if (!parsed.hostname.includes("cdn.sanity.io")) {
      return url;
    }
    if (!parsed.searchParams.get("fm")) {
      parsed.searchParams.set("fm", "png");
    }
    return parsed.toString();
  } catch {
    return url;
  }
}

async function fetchLogoBytes(logoUrl?: string) {
  const raw = (logoUrl || "").trim();
  if (!raw) {
    return null;
  }

  const resolved = withSanityPngFormat(raw);

  try {
    const response = await fetch(resolved, { cache: "no-store" });
    if (!response.ok) {
      return null;
    }

    const contentType = (response.headers.get("content-type") || "").toLowerCase();
    const bytes = await response.arrayBuffer();
    const uint8 = new Uint8Array(bytes);

    if (contentType.includes("png") || contentType.includes("jpeg") || contentType.includes("jpg")) {
      return { bytes: uint8, contentType };
    }

    const lowerUrl = resolved.toLowerCase();
    if (lowerUrl.endsWith(".png")) {
      return { bytes: uint8, contentType: "image/png" };
    }
    if (lowerUrl.endsWith(".jpg") || lowerUrl.endsWith(".jpeg")) {
      return { bytes: uint8, contentType: "image/jpeg" };
    }

    return null;
  } catch {
    return null;
  }
}

export async function buildQuotePdf({ quote, customerAddress, settings }: QuotePdfData) {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([595, 842]);
  const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
  const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
  const accent = parseHexColor(settings?.accentHexColor);
  const currencyCode = quote.currency_code || "eur";

  const companyName = settings?.companyName || legalInfo.companyName;
  const companyAddress = settings?.companyAddress || legalInfo.postalAddress;
  const companyEmail = settings?.companyEmail || legalInfo.contactEmail;
  const vatNumber = settings?.vatNumber || legalInfo.vatNumber;
  const quoteTitle = settings?.quoteTitle || "Devis";
  const footerNote = settings?.footerNote || "Merci pour votre demande.";
  const paymentTerms = settings?.paymentTerms || "";
  const introText = settings?.introText || "";
  const logoData = await fetchLogoBytes(settings?.logoUrl);
  const expirationDate = getQuoteExpirationDate(quote.created_at);

  const cartSnapshot = (quote.cart_snapshot && typeof quote.cart_snapshot === "object" ? quote.cart_snapshot : {}) as {
    customer_email?: string;
    email?: string;
    shipping_address?: {
      first_name?: string;
      last_name?: string;
      address_1?: string;
      postal_code?: string;
      city?: string;
      country_code?: string;
    } | null;
  };

  const leftX = 40;
  const rightX = 430;
  const tableQtyX = 330;
  const tableUnitX = 400;
  const tableTotalX = 490;
  const contentRightX = 555;
  const pageTopY = 800;
  const footerTopY = 70;
  let companyTopY = pageTopY;
  const quoteTopY = pageTopY;

  if (logoData) {
    try {
      const logoImage = logoData.contentType.includes("png")
        ? await pdfDoc.embedPng(logoData.bytes)
        : await pdfDoc.embedJpg(logoData.bytes);
      const source = logoImage.scale(1);
      const maxWidth = 140;
      const maxHeight = 56;
      const ratio = Math.min(maxWidth / source.width, maxHeight / source.height, 1);
      const width = source.width * ratio;
      const height = source.height * ratio;
      const logoTopY = 812;

      page.drawImage(logoImage, {
        x: leftX,
        y: logoTopY - height,
        width,
        height,
      });

      companyTopY = logoTopY - height - 14;
    } catch {
      // Ignore invalid logo payloads.
    }
  }

  let y = companyTopY;
  page.drawText(companyName, { x: leftX, y, size: 18, font: fontBold, color: accent });
  y -= 22;
  const companyLines = [
    ...toLines(companyAddress),
    ...toLines(companyEmail),
    ...toLines(vatNumber ? `TVA: ${vatNumber}` : ""),
  ];
  if (companyLines.length > 0) {
    y = drawTextLines(page, companyLines, { x: leftX, y, size: 10, font, lineGap: 4 });
  }
  const companyBottomY = y + 14;

  page.drawText(quoteTitle, { x: rightX, y: quoteTopY, size: 18, font: fontBold, color: accent });
  page.drawText(`Reference: ${quote.reference || "-"}`, {
    x: rightX,
    y: quoteTopY - 22,
    size: 10,
    font,
  });
  page.drawText(`Date: ${formatDate(quote.created_at)}`, { x: rightX, y: quoteTopY - 36, size: 10, font });
  if (expirationDate) {
    page.drawText(`Expiration: ${formatDate(expirationDate)}`, { x: rightX, y: quoteTopY - 50, size: 10, font });
  }
  const quoteBottomY = expirationDate ? quoteTopY - 50 : quoteTopY - 36;

  y = Math.min(companyBottomY, quoteBottomY) - 20;
  page.drawLine({ start: { x: leftX, y }, end: { x: contentRightX, y }, thickness: 1, color: rgb(0.9, 0.9, 0.9) });
  y -= 24;
  page.drawText("Client", { x: leftX, y, size: 12, font: fontBold });
  y -= 16;
  const customer = customerAddress || cartSnapshot.shipping_address || null;
  const customerName = [customer?.first_name, customer?.last_name].filter(Boolean).join(" ");
  const addressLine = [
    customer?.address_1,
    customer?.postal_code,
    customer?.city,
    customer?.country_code?.toUpperCase(),
  ]
    .filter(Boolean)
    .join(", ");
  y = drawTextLines(
    page,
    [customerName || "Client", cartSnapshot.customer_email || cartSnapshot.email || quote.customer_email || "-", addressLine || "-"],
    { x: leftX, y, size: 10, font, lineGap: 4 },
  );
  y -= 18;
  if (quote.event_date) {
    page.drawText(`Date evenement: ${quote.event_date}`, { x: leftX, y, size: 10, font });
    y -= 16;
  }
  if (introText) {
    const introLines = toLines(introText).map((line) => line.slice(0, 110));
    y = drawTextLines(page, introLines, { x: leftX, y, size: 9, font, color: rgb(0.35, 0.35, 0.35), lineGap: 3 });
    y -= 10;
  }

  page.drawText("Articles", { x: leftX, y, size: 12, font: fontBold });
  y -= 20;
  page.drawText("Designation", { x: leftX, y, size: 10, font: fontBold });
  page.drawText("Qte", { x: tableQtyX, y, size: 10, font: fontBold });
  page.drawText("Prix unitaire", { x: tableUnitX, y, size: 10, font: fontBold });
  page.drawText("Total", { x: tableTotalX, y, size: 10, font: fontBold });
  y -= 10;
  page.drawLine({ start: { x: leftX, y }, end: { x: contentRightX, y }, thickness: 1, color: rgb(0.9, 0.9, 0.9) });
  y -= 16;

  const items = Array.isArray(quote.items) ? quote.items : [];
  const minimumSummaryStartY = footerTopY + 90;
  for (const item of items.slice(0, 18)) {
    const title = item.product_title || "Article";
    const variant = item.variant_title ? ` - ${item.variant_title}` : "";
    const quantity = Math.max(1, item.quantity || 1);
    const unitAmount =
      typeof item.unit_price === "number"
        ? item.unit_price
        : typeof item.total === "number"
        ? Math.round(item.total / quantity)
        : null;
    page.drawText(`${title}${variant}`.slice(0, 60), { x: leftX, y, size: 10, font });
    page.drawText(String(quantity), { x: tableQtyX, y, size: 10, font });
    page.drawText(formatCurrency(unitAmount, currencyCode), { x: tableUnitX, y, size: 10, font });
    page.drawText(formatCurrency(item.total, currencyCode), { x: tableTotalX, y, size: 10, font });
    y -= 16;
    if (y < minimumSummaryStartY) {
      break;
    }
  }

  y = Math.max(y, minimumSummaryStartY);
  y -= 10;
  page.drawLine({ start: { x: 320, y }, end: { x: contentRightX, y }, thickness: 1, color: rgb(0.9, 0.9, 0.9) });
  y -= 18;
  page.drawText(`Sous-total: ${formatCurrency(quote.subtotal, currencyCode)}`, { x: tableQtyX, y, size: 10, font });
  y -= 14;
  page.drawText(`Livraison: ${formatCurrency(quote.shipping_total, currencyCode)}`, { x: tableQtyX, y, size: 10, font });
  y -= 18;
  page.drawText(`Total: ${formatCurrency(quote.total, currencyCode)}`, { x: tableQtyX, y, size: 12, font: fontBold });

  const footerLines = [...toLines(footerNote), ...toLines(paymentTerms)];
  if (footerLines.length > 0) {
    drawTextLines(page, footerLines, {
      x: leftX,
      y: footerTopY,
      size: 9,
      font,
      color: rgb(0.35, 0.35, 0.35),
      lineGap: 3,
    });
  }

  return pdfDoc.save();
}
