import type { DocPageLayout } from "@/lib/drive/doc-page-setup"
import type { DocsExportSnapshot } from "@/lib/drive/docs-export-snapshot"
import { captureDocsPagesFromCanvas } from "@/lib/drive/docs-page-capture"

const PRINT_IFRAME_ID = "docs-print-iframe"

function buildPageRule(pageLayout: DocPageLayout): string {
  const wMm = pageLayout.format.widthMm
  const hMm = pageLayout.format.heightMm
  const landscape = pageLayout.format.widthMm > pageLayout.format.heightMm
  const size = landscape ? `${hMm}mm ${wMm}mm` : `${wMm}mm ${hMm}mm`
  return `@page { size: ${size}; margin: 0; }`
}

function buildPrintStylesheet(pageLayout: DocPageLayout): string {
  const pageWidth = pageLayout.widthPx
  const pageHeight = pageLayout.heightPx
  return `
${buildPageRule(pageLayout)}
html, body {
  margin: 0;
  padding: 0;
  background: white;
}
.docs-print-page {
  width: ${pageWidth}px;
  height: ${pageHeight}px;
  overflow: hidden;
  break-after: page;
  page-break-after: always;
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}
.docs-print-page:last-child {
  break-after: auto;
  page-break-after: auto;
}
.docs-print-page img {
  display: block;
  width: 100%;
  height: 100%;
}
`
}

function canvasToBlob(canvas: HTMLCanvasElement): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (blob) resolve(blob)
        else reject(new Error("Impossible de convertir la page en image"))
      },
      "image/jpeg",
      0.92
    )
  })
}

function removePrintIframe(): void {
  document.getElementById(PRINT_IFRAME_ID)?.remove()
}

async function mountPrintDocument(
  doc: Document,
  canvases: HTMLCanvasElement[],
  pageLayout: DocPageLayout
): Promise<() => void> {
  const pageWidth = pageLayout.widthPx
  const pageHeight = pageLayout.heightPx
  const objectUrls: string[] = []

  doc.documentElement.lang = "fr"
  doc.head.replaceChildren()
  doc.body.replaceChildren()

  const style = doc.createElement("style")
  style.textContent = buildPrintStylesheet(pageLayout)
  doc.head.appendChild(style)

  for (const canvas of canvases) {
    const blob = await canvasToBlob(canvas)
    const url = URL.createObjectURL(blob)
    objectUrls.push(url)

    const page = doc.createElement("div")
    page.className = "docs-print-page"
    page.style.width = `${pageWidth}px`
    page.style.height = `${pageHeight}px`

    const img = doc.createElement("img")
    img.alt = ""
    img.width = pageWidth
    img.height = pageHeight
    img.src = url

    page.appendChild(img)
    doc.body.appendChild(page)
    await img.decode().catch(() => undefined)
  }

  return () => {
    for (const url of objectUrls) {
      URL.revokeObjectURL(url)
    }
  }
}

async function printPageCanvasesInIframe(
  canvases: HTMLCanvasElement[],
  pageLayout: DocPageLayout
): Promise<void> {
  if (canvases.length === 0) {
    throw new Error("Aucune page à imprimer")
  }

  removePrintIframe()

  const iframe = document.createElement("iframe")
  iframe.id = PRINT_IFRAME_ID
  iframe.setAttribute("aria-hidden", "true")
  iframe.style.cssText =
    "position:fixed;left:-100000px;top:0;width:1px;height:1px;border:0;opacity:0;pointer-events:none"

  const docReady = new Promise<Document>((resolve, reject) => {
    iframe.onload = () => {
      const doc = iframe.contentDocument
      if (doc) resolve(doc)
      else reject(new Error("Impossible de préparer la fenêtre d'impression"))
    }
    iframe.onerror = () => reject(new Error("Impossible de préparer la fenêtre d'impression"))
  })

  iframe.src = "about:blank"
  document.body.appendChild(iframe)

  const doc = await docReady
  const win = iframe.contentWindow
  if (!win) {
    removePrintIframe()
    throw new Error("Impossible de préparer la fenêtre d'impression")
  }

  let revokeObjectUrls = () => {}
  try {
    revokeObjectUrls = await mountPrintDocument(doc, canvases, pageLayout)

    await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))
    if (doc.fonts?.ready) {
      await doc.fonts.ready
    }

    await new Promise<void>((resolve, reject) => {
      const cleanup = () => {
        win.removeEventListener("afterprint", onAfterPrint)
        revokeObjectUrls()
        removePrintIframe()
      }

      const onAfterPrint = () => {
        cleanup()
        resolve()
      }

      win.addEventListener("afterprint", onAfterPrint)

      try {
        win.focus()
        win.print()
      } catch (error) {
        cleanup()
        reject(error)
        return
      }

      window.setTimeout(() => {
        if (document.getElementById(PRINT_IFRAME_ID)) {
          cleanup()
          resolve()
        }
      }, 2000)
    })
  } catch (error) {
    revokeObjectUrls()
    removePrintIframe()
    throw error
  }
}

export type DocsPrintMode = "print" | "pdf-capture"

/** @deprecated Live DOM is no longer mutated; kept for PDF export compatibility. */
export async function prepareDocsPrintEnvironment(
  _snapshot: DocsExportSnapshot,
  _mode: DocsPrintMode = "print"
): Promise<() => void> {
  return () => {}
}

export async function printDocsDocument(snapshot: DocsExportSnapshot): Promise<void> {
  const canvases = await captureDocsPagesFromCanvas(snapshot, { scale: 2 })
  await printPageCanvasesInIframe(canvases, snapshot.pageLayout)
}
