import { createRoot } from 'react-dom/client';
import { createElement } from 'react';
import { jsPDF } from 'jspdf';
import html2canvas from 'html2canvas';
import {
  CaseSheetPrintLayout,
  type CaseSheetLabels,
} from '@/components/ui/lab/CaseSheetPrintLayout';
import type { LabCaseDetail } from '@/types/cases';
import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog';

type DownloadCaseSheetPdfArgs = {
  labCase: LabCaseDetail;
  locale: string;
  labels: CaseSheetLabels;
  prosthesisCatalog: readonly ProsthesisCatalogEntry[];
  fileName?: string;
};

function waitForPaint(): Promise<void> {
  return new Promise((resolve) => {
    requestAnimationFrame(() => {
      requestAnimationFrame(() => resolve());
    });
  });
}

/**
 * Renders an off-screen Case Sheet, captures it, and downloads an A4 PDF
 * (ISO A-series √2 ratio — prints cleanly onto A3–A6).
 *
 * Print layout uses hex-only inline styles so html2canvas is not fed Tailwind
 * `lab()` / `oklch()` from global stylesheets.
 */
export async function downloadCaseSheetPdf({
  labCase,
  locale,
  labels,
  prosthesisCatalog,
  fileName,
}: DownloadCaseSheetPdfArgs): Promise<void> {
  const host = document.createElement('div');
  host.setAttribute('aria-hidden', 'true');
  host.style.cssText =
    'position:fixed;left:-12000px;top:0;z-index:-1;pointer-events:none;opacity:1;';
  document.body.appendChild(host);

  const root = createRoot(host);
  try {
    root.render(
      createElement(CaseSheetPrintLayout, {
        labCase,
        locale,
        labels,
        prosthesisCatalog,
      }),
    );
    await waitForPaint();
    await new Promise((r) => setTimeout(r, 80));

    const sheet = host.querySelector('[data-case-sheet-root]');
    if (!(sheet instanceof HTMLElement)) {
      throw new Error('Case sheet root not found');
    }

    const canvas = await html2canvas(sheet, {
      scale: 2,
      backgroundColor: '#ffffff',
      useCORS: true,
      logging: false,
      // Drop app stylesheets so parsers never see lab()/oklch() from Tailwind.
      onclone: (clonedDoc) => {
        clonedDoc
          .querySelectorAll('style, link[rel="stylesheet"]')
          .forEach((node) => node.remove());
      },
    });

    const pdf = new jsPDF({
      orientation: 'portrait',
      unit: 'mm',
      format: 'a4',
    });
    const pageWidth = pdf.internal.pageSize.getWidth();
    const pageHeight = pdf.internal.pageSize.getHeight();
    const margin = 8;
    const usableWidth = pageWidth - margin * 2;
    const usableHeight = pageHeight - margin * 2;

    const imgData = canvas.toDataURL('image/png');
    const imgHeight = (canvas.height * usableWidth) / canvas.width;

    if (imgHeight <= usableHeight) {
      pdf.addImage(imgData, 'PNG', margin, margin, usableWidth, imgHeight);
    } else {
      let remainingHeightPx = canvas.height;
      let sourceY = 0;
      const pageHeightPx = (usableHeight * canvas.width) / usableWidth;
      let pageIndex = 0;

      while (remainingHeightPx > 0) {
        if (pageIndex > 0) pdf.addPage();
        const sliceHeight = Math.min(pageHeightPx, remainingHeightPx);
        const pageCanvas = document.createElement('canvas');
        pageCanvas.width = canvas.width;
        pageCanvas.height = sliceHeight;
        const ctx = pageCanvas.getContext('2d');
        if (!ctx) break;
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
        ctx.drawImage(
          canvas,
          0,
          sourceY,
          canvas.width,
          sliceHeight,
          0,
          0,
          canvas.width,
          sliceHeight,
        );
        const sliceData = pageCanvas.toDataURL('image/png');
        const sliceMm = (sliceHeight * usableWidth) / canvas.width;
        pdf.addImage(sliceData, 'PNG', margin, margin, usableWidth, sliceMm);
        sourceY += sliceHeight;
        remainingHeightPx -= sliceHeight;
        pageIndex += 1;
      }
    }

    const safeName =
      fileName ??
      `case-sheet-${labCase.id.replace(/-/g, '').slice(0, 8)}.pdf`;
    pdf.save(safeName);
  } finally {
    root.unmount();
    host.remove();
  }
}
