"use client"

import {
  useCallback,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
  type CSSProperties,
} from "react"
import { useTheme } from "next-themes"
import {
  emailPreviewBaseCss,
  emailPreviewDarkOverrideCss,
  emailPreviewDarkRemoteBodyTailCss,
  emailPreviewDarkTailOverrideCss,
  emailPreviewLightOverrideCss,
  emailPreviewWrapperCss,
} from "@/lib/email-preview-dark-styles"
import {
  EMAIL_PREVIEW_MIN_IFRAME_HEIGHT,
  measureEmailPreviewIframeHeight,
  resolveEmailPreviewMeasureRoot,
} from "@/lib/email-preview-iframe-height"
import {
  buildEmailPreviewSrcdoc,
  prepareEmailHtmlForIframe,
} from "@/lib/mail-html-iframe"
import { buildEmailPreviewCsp } from "@/lib/mail-remote-content"
import {
  isEmailPreviewContrastDebugEnabled,
  logEmailPreviewContrastIssues,
  repairEmailPreviewContrast,
} from "@/lib/email-preview-contrast"

const EMAIL_PREVIEW_IFRAME_STYLE: CSSProperties = {
  display: "block",
  background: "transparent",
  overflow: "hidden",
}

function documentIsDark(): boolean {
  return document.documentElement.classList.contains("dark")
}

function bindEmailPreviewImageLoads(
  root: HTMLElement,
  onChange: () => void
): () => void {
  const images = root.querySelectorAll("img")
  if (images.length === 0) return () => {}

  let pending = 0
  const onDone = () => {
    pending -= 1
    if (pending <= 0) onChange()
  }

  for (const img of images) {
    if (img.complete) continue
    pending += 1
    img.addEventListener("load", onDone, { once: true })
    img.addEventListener("error", onDone, { once: true })
  }

  if (pending === 0) return () => {}

  return () => {
    for (const img of images) {
      img.removeEventListener("load", onDone)
      img.removeEventListener("error", onDone)
    }
  }
}

export function SandboxedContent({
  html,
  blockRemoteContent,
  restrictPopups = false,
  senderEmail,
  cidUrlMap,
  plainTextFallback,
  messageId,
  previewPart = "body",
}: {
  html: string
  blockRemoteContent: boolean
  restrictPopups?: boolean
  senderEmail?: string
  cidUrlMap?: Record<string, string>
  /** Plain body when HTML is image-only or empty with remote content blocked. */
  plainTextFallback?: string
  /** Pour les logs dev [email-preview:low-contrast]. */
  messageId?: string
  previewPart?: "body" | "quoted"
}) {
  const iframeRef = useRef<HTMLIFrameElement>(null)
  const contrastLoggedKeyRef = useRef<string | null>(null)
  const contrastDelayTimerRef = useRef<number | null>(null)
  const resizeObserverRef = useRef<ResizeObserver | null>(null)
  const unbindImageLoadsRef = useRef<(() => void) | null>(null)
  const contentGenerationRef = useRef(0)
  const appliedHeightRef = useRef(EMAIL_PREVIEW_MIN_IFRAME_HEIGHT)
  const syncRafRef = useRef<number | null>(null)
  const [height, setHeight] = useState(EMAIL_PREVIEW_MIN_IFRAME_HEIGHT)

  const sandboxValue = restrictPopups
    ? "allow-same-origin"
    : "allow-same-origin allow-popups"

  const { resolvedTheme } = useTheme()
  const isDark =
    resolvedTheme === "dark" ||
    ((resolvedTheme === "system" || resolvedTheme === undefined) &&
      typeof document !== "undefined" &&
      documentIsDark())

  const parsedEmail = useMemo(
    () =>
      prepareEmailHtmlForIframe(html, {
        blockRemoteContent,
        isDark,
        senderEmail,
        cidUrlMap,
        plainTextFallback,
      }),
    [html, blockRemoteContent, isDark, senderEmail, cidUrlMap, plainTextFallback]
  )

  const themeCss = useMemo(() => {
    if (!blockRemoteContent) {
      const wrapper = emailPreviewWrapperCss(isDark)
      return isDark ? `${wrapper}${emailPreviewDarkOverrideCss()}` : wrapper
    }
    return `${emailPreviewBaseCss(isDark)}${
      isDark ? emailPreviewDarkOverrideCss() : emailPreviewLightOverrideCss()
    }`
  }, [blockRemoteContent, isDark])

  const cspContent = useMemo(
    () => buildEmailPreviewCsp(blockRemoteContent),
    [blockRemoteContent]
  )

  const srcdoc = useMemo(
    () =>
      buildEmailPreviewSrcdoc(parsedEmail, {
        csp: cspContent,
        wrapperCss: themeCss,
        plainTextFallback,
        loadAppFont: !blockRemoteContent,
        bodyTailCss: isDark
          ? blockRemoteContent
            ? emailPreviewDarkTailOverrideCss()
            : emailPreviewDarkRemoteBodyTailCss()
          : undefined,
      }),
    [
      parsedEmail,
      cspContent,
      themeCss,
      plainTextFallback,
      isDark,
      blockRemoteContent,
    ]
  )

  const iframeKey = `${messageId ?? "no-id"}:${previewPart}:${blockRemoteContent ? "remote-blocked" : "remote-allowed"}:${isDark ? "dark" : "light"}`

  const applyMeasuredHeight = useCallback((generation: number) => {
    if (generation !== contentGenerationRef.current) return
    const doc = iframeRef.current?.contentDocument
    if (!doc) return

    const next = measureEmailPreviewIframeHeight(doc)
    if (appliedHeightRef.current === next) return
    appliedHeightRef.current = next
    setHeight(next)
  }, [])

  const scheduleHeightSync = useCallback(
    (generation: number) => {
      if (syncRafRef.current !== null) {
        cancelAnimationFrame(syncRafRef.current)
      }
      syncRafRef.current = requestAnimationFrame(() => {
        syncRafRef.current = requestAnimationFrame(() => {
          syncRafRef.current = null
          applyMeasuredHeight(generation)
        })
      })
    },
    [applyMeasuredHeight]
  )

  const runContrastPipeline = useCallback(
    (doc: Document, pass: "initial" | "delayed", generation: number) => {
      if (!isDark || generation !== contentGenerationRef.current) return

      const repair = repairEmailPreviewContrast(doc, {
        isDark: true,
        repairMode: blockRemoteContent ? "dark-only" : "all",
        newsletterLightCanvas: false,
        assumedCanvasRgb: [32, 33, 36],
      })

      if (repair && (repair.lightSurfaces > 0 || repair.darkSurfaces > 0)) {
        scheduleHeightSync(generation)
        if (isEmailPreviewContrastDebugEnabled()) {
          console.info("[email-preview:contrast-repaired]", {
            messageId,
            part: previewPart,
            pass,
            blockRemoteContent,
            ...repair,
          })
        }
      }

      if (!isEmailPreviewContrastDebugEnabled()) return

      const logKey = `${messageId ?? "no-id"}:${previewPart}:${blockRemoteContent}:${isDark}:${srcdoc.length}:${pass}`
      if (contrastLoggedKeyRef.current === logKey) return
      contrastLoggedKeyRef.current = logKey
      logEmailPreviewContrastIssues(
        {
          messageId,
          part: previewPart,
          blockRemoteContent,
          isDark,
          senderEmail,
        },
        doc,
        { newsletterLightCanvas: false, assumedCanvasRgb: [32, 33, 36] }
      )
    },
    [
      messageId,
      previewPart,
      blockRemoteContent,
      isDark,
      senderEmail,
      srcdoc,
      scheduleHeightSync,
    ]
  )

  const handleIframeLoad = useCallback(() => {
    const generation = contentGenerationRef.current
    const doc = iframeRef.current?.contentDocument
    const measureRoot = doc ? resolveEmailPreviewMeasureRoot(doc) : null

    resizeObserverRef.current?.disconnect()
    unbindImageLoadsRef.current?.()
    unbindImageLoadsRef.current = null

    if (measureRoot) {
      resizeObserverRef.current = new ResizeObserver(() => {
        scheduleHeightSync(generation)
      })
      resizeObserverRef.current.observe(measureRoot)

      unbindImageLoadsRef.current = bindEmailPreviewImageLoads(measureRoot, () => {
        scheduleHeightSync(generation)
      })
    }

    scheduleHeightSync(generation)
    if (doc) runContrastPipeline(doc, "initial", generation)

    if (contrastDelayTimerRef.current !== null) {
      window.clearTimeout(contrastDelayTimerRef.current)
    }
    contrastDelayTimerRef.current = window.setTimeout(() => {
      contrastDelayTimerRef.current = null
      if (generation !== contentGenerationRef.current) return
      const lateDoc = iframeRef.current?.contentDocument
      if (lateDoc) {
        scheduleHeightSync(generation)
        runContrastPipeline(lateDoc, "delayed", generation)
      }
    }, 1000)
  }, [scheduleHeightSync, runContrastPipeline])

  useLayoutEffect(() => {
    contentGenerationRef.current += 1
    appliedHeightRef.current = EMAIL_PREVIEW_MIN_IFRAME_HEIGHT
    setHeight(EMAIL_PREVIEW_MIN_IFRAME_HEIGHT)
    contrastLoggedKeyRef.current = null
    resizeObserverRef.current?.disconnect()
    resizeObserverRef.current = null
    unbindImageLoadsRef.current?.()
    unbindImageLoadsRef.current = null
    if (syncRafRef.current !== null) {
      cancelAnimationFrame(syncRafRef.current)
      syncRafRef.current = null
    }
    if (contrastDelayTimerRef.current !== null) {
      window.clearTimeout(contrastDelayTimerRef.current)
      contrastDelayTimerRef.current = null
    }
  }, [srcdoc, messageId])

  return (
    <iframe
      key={iframeKey}
      ref={iframeRef}
      sandbox={sandboxValue}
      scrolling="no"
      title="Contenu du message"
      className="w-full border-0 bg-transparent"
      style={{ ...EMAIL_PREVIEW_IFRAME_STYLE, height: `${height}px` }}
      srcDoc={srcdoc}
      onLoad={handleIframeLoad}
      tabIndex={-1}
    />
  )
}
