import type Konva from 'konva';
import type { jsPDF as JsPDFType } from 'jspdf';

// ── PNG Export Options ──

export interface PngExportOptions {
  readonly pixelRatio?: number;
  readonly mimeType?: 'image/png' | 'image/jpeg';
  readonly quality?: number;
}

// ── Stage-based PNG export ──

/**
 * Export a Konva stage to a data URL.
 * Optionally hides the grid layer before exporting.
 */
export function exportKonvaStageToDataUrl(
  stage: Konva.Stage,
  options: PngExportOptions & { readonly includeGrid?: boolean } = {},
): string {
  const { pixelRatio = 2, mimeType = 'image/png', quality = 1, includeGrid = false } = options;

  // Temporarily hide grid layer if requested (only for multi-layer stages like the 2D editor)
  const layers = stage.getLayers();
  // Grid is the first layer only when there are multiple layers (2D editor).
  // Single-layer stages (projections) should never have their layer hidden.
  const gridLayer = layers.length > 1 ? layers[0] : null;
  const gridWasVisible = gridLayer?.visible() ?? false;

  if (!includeGrid && gridLayer) {
    gridLayer.visible(false);
    stage.draw();
  }

  // Force a synchronous redraw before capture
  stage.draw();

  const dataUrl = stage.toDataURL({
    pixelRatio,
    mimeType,
    quality,
    x: 0,
    y: 0,
    width: stage.width(),
    height: stage.height(),
  });

  // Restore grid visibility
  if (!includeGrid && gridLayer && gridWasVisible) {
    gridLayer.visible(true);
    stage.draw();
  }

  return dataUrl;
}

/**
 * Export a Three.js canvas element to a data URL.
 */
export function exportThreeCanvasToDataUrl(
  canvas: HTMLCanvasElement,
): string {
  return canvas.toDataURL('image/png');
}

// ── Download helpers ──

/**
 * Trigger browser download of a data URL as a file.
 */
export function downloadDataUrl(dataUrl: string, filename: string): void {
  const link = document.createElement('a');
  link.download = filename;
  link.href = dataUrl;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

/**
 * Trigger browser download of a Blob.
 */
export function downloadBlob(blob: Blob, filename: string): void {
  const url = URL.createObjectURL(blob);
  downloadDataUrl(url, filename);
  URL.revokeObjectURL(url);
}

// ── PDF Export ──

export interface PdfExportOptions {
  readonly title: string;
  readonly includeGrid?: boolean;
  readonly pixelRatio?: number;
}

/**
 * Lazy-load jsPDF for code splitting.
 */
async function loadJsPDF(): Promise<typeof import('jspdf')> {
  return import('jspdf');
}

/**
 * Create a single-room PDF with:
 * - Room name header
 * - 2D top-down view
 * - Up to 4 wall projection views
 */
export async function createRoomPdf(
  roomName: string,
  topDownDataUrl: string | null,
  projectionDataUrls: readonly { readonly label: string; readonly dataUrl: string }[],
  view3dDataUrl: string | null,
): Promise<JsPDFType> {
  const { jsPDF } = await loadJsPDF();
  const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' });
  const pageWidth = pdf.internal.pageSize.getWidth();
  const pageHeight = pdf.internal.pageSize.getHeight();

  // ── Page 1: Room name + 2D view ──
  pdf.setFontSize(18);
  pdf.text(roomName, pageWidth / 2, 15, { align: 'center' });

  if (topDownDataUrl) {
    const imgWidth = pageWidth - 30;
    const imgHeight = (pageHeight - 40) * 0.55;
    pdf.addImage(topDownDataUrl, 'PNG', 15, 25, imgWidth, imgHeight);
  }

  // ── Page 2: Wall projections (if any) ──
  if (projectionDataUrls.length > 0) {
    pdf.addPage('a4', 'landscape');
    pdf.setFontSize(14);
    pdf.text(`${roomName} - Wall Projections`, pageWidth / 2, 15, { align: 'center' });

    const cols = 2;
    const rows = 2;
    const cellW = (pageWidth - 30) / cols;
    const cellH = (pageHeight - 35) / rows;

    for (let i = 0; i < Math.min(projectionDataUrls.length, 4); i++) {
      const col = i % cols;
      const row = Math.floor(i / cols);
      const x = 15 + col * cellW;
      const y = 22 + row * cellH;

      const proj = projectionDataUrls[i];
      pdf.setFontSize(9);
      pdf.text(proj.label, x + cellW / 2, y + 2, { align: 'center' });
      pdf.addImage(proj.dataUrl, 'PNG', x + 2, y + 5, cellW - 4, cellH - 10);
    }
  }

  // ── Page 3: 3D view (if available) ──
  if (view3dDataUrl) {
    pdf.addPage('a4', 'landscape');
    pdf.setFontSize(14);
    pdf.text(`${roomName} - 3D View`, pageWidth / 2, 15, { align: 'center' });

    const imgWidth = pageWidth - 30;
    const imgHeight = pageHeight - 30;
    pdf.addImage(view3dDataUrl, 'PNG', 15, 20, imgWidth, imgHeight);
  }

  return pdf;
}

/**
 * Create a multi-room apartment PDF with a cover page.
 */
export async function createApartmentPdf(
  apartmentName: string,
  rooms: readonly {
    readonly roomName: string;
    readonly topDownDataUrl: string | null;
    readonly projectionDataUrls: readonly { readonly label: string; readonly dataUrl: string }[];
  }[],
): Promise<JsPDFType> {
  const { jsPDF } = await loadJsPDF();
  const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' });
  const pageWidth = pdf.internal.pageSize.getWidth();
  const pageHeight = pdf.internal.pageSize.getHeight();

  // ── Cover page ──
  pdf.setFontSize(28);
  pdf.text(apartmentName, pageWidth / 2, pageHeight / 3, { align: 'center' });
  pdf.setFontSize(14);
  pdf.text('House Plan', pageWidth / 2, pageHeight / 3 + 12, { align: 'center' });
  pdf.setFontSize(10);
  pdf.text(`Generated: ${new Date().toLocaleDateString()}`, pageWidth / 2, pageHeight / 3 + 22, { align: 'center' });
  pdf.setFontSize(11);
  pdf.text(
    `${rooms.length} room${rooms.length === 1 ? '' : 's'}`,
    pageWidth / 2,
    pageHeight / 3 + 30,
    { align: 'center' },
  );

  // ── Room pages ──
  for (const room of rooms) {
    pdf.addPage('a4', 'landscape');
    pdf.setFontSize(18);
    pdf.text(room.roomName, pageWidth / 2, 15, { align: 'center' });

    if (room.topDownDataUrl) {
      const imgWidth = pageWidth - 30;
      const imgHeight = (pageHeight - 40) * 0.55;
      pdf.addImage(room.topDownDataUrl, 'PNG', 15, 25, imgWidth, imgHeight);
    }

    // Projections page
    if (room.projectionDataUrls.length > 0) {
      pdf.addPage('a4', 'landscape');
      pdf.setFontSize(14);
      pdf.text(`${room.roomName} - Wall Projections`, pageWidth / 2, 15, { align: 'center' });

      const cols = 2;
      const rows = 2;
      const cellW = (pageWidth - 30) / cols;
      const cellH = (pageHeight - 35) / rows;

      for (let i = 0; i < Math.min(room.projectionDataUrls.length, 4); i++) {
        const col = i % cols;
        const row = Math.floor(i / cols);
        const x = 15 + col * cellW;
        const y = 22 + row * cellH;

        const proj = room.projectionDataUrls[i];
        pdf.setFontSize(9);
        pdf.text(proj.label, x + cellW / 2, y + 2, { align: 'center' });
        pdf.addImage(proj.dataUrl, 'PNG', x + 2, y + 5, cellW - 4, cellH - 10);
      }
    }
  }

  return pdf;
}

/**
 * Sanitize a filename for download.
 */
export function sanitizeFilename(name: string): string {
  return name.replace(/[^a-zA-Z0-9_\-\s]/g, '').replace(/\s+/g, '_');
}
