"use client"

import { useLayoutEffect, useRef, useState } from "react"
import { cn } from "@/lib/utils"

export type ScaledPreviewFit = "contain" | "cover"

export type ScaledPreviewIframeProps = {
  src: string
  title: string
  viewportWidth: number
  viewportHeight: number
  ready?: boolean
  active?: boolean
  /**
   * contain = letterbox si le ratio parent ≠ ratio viewport ;
   * cover = remplit (recadrage éventuel, seulement les coins si ratios proches).
   * Idéalement le parent porte un aspect-ratio = viewportWidth/viewportHeight,
   * auquel cas contain et cover sont équivalents (aucune coupe).
   */
  fit?: ScaledPreviewFit
  /** Débord de sécurité (px) en mode cover — évite les hairlines aux bords/coins. */
  coverEpsilonPx?: number
  maxScale?: number
  className?: string
  placeholderClassName?: string
}

/**
 * Iframe à viewport logique fixe (rendu « grand écran »), affichée à la taille
 * du parent. Le `transform: scale` est porté par un <div> wrapper dimensionné
 * au viewport ; l'iframe est en `absolute inset-0` et remplit ce wrapper à
 * 100 % (WebKit scale mal une iframe directement). Aucun aspect-ratio n'est
 * posé sur l'iframe : c'est au(x) parent(s) redimensionnable(s) de le porter.
 */
export function ScaledPreviewIframe({
  src,
  title,
  viewportWidth,
  viewportHeight,
  ready = true,
  active = true,
  fit = "cover",
  coverEpsilonPx = 1,
  maxScale,
  className,
  placeholderClassName,
}: ScaledPreviewIframeProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  /** null = pas encore mesuré (évite un iframe à scale par défaut au 1er paint). */
  const [scale, setScale] = useState<number | null>(null)

  useLayoutEffect(() => {
    if (!ready) {
      setScale(null)
      return
    }

    const node = containerRef.current
    if (!node) return

    const update = () => {
      // offsetWidth/Height = taille de layout SANS les transforms des ancêtres.
      const width = node.offsetWidth
      const height = node.offsetHeight
      if (width <= 0 || height <= 0) return

      let next: number
      if (fit === "cover") {
        const eps = coverEpsilonPx
        next = Math.max(
          (width + eps) / viewportWidth,
          (height + eps) / viewportHeight
        )
      } else {
        next = Math.min(width / viewportWidth, height / viewportHeight)
      }

      if (maxScale !== undefined) next = Math.min(next, maxScale)
      setScale(next)
    }

    update()
    const raf1 = requestAnimationFrame(() => {
      update()
      requestAnimationFrame(update)
    })

    const observer = new ResizeObserver(update)
    observer.observe(node)
    window.addEventListener("load", update, { once: true })

    return () => {
      cancelAnimationFrame(raf1)
      observer.disconnect()
      window.removeEventListener("load", update)
    }
  }, [ready, viewportWidth, viewportHeight, fit, coverEpsilonPx, maxScale])

  return (
    <div
      ref={containerRef}
      className={cn("relative h-full w-full overflow-hidden", className)}
    >
      {ready && scale !== null ? (
        <div
          className="absolute left-1/2 top-1/2"
          style={{
            width: viewportWidth,
            height: viewportHeight,
            transform: `translate(-50%, -50%) scale(${scale})`,
            transformOrigin: "center center",
          }}
        >
          <iframe
            src={src}
            title={title}
            loading="lazy"
            scrolling="no"
            tabIndex={active ? 0 : -1}
            className={cn(
              "absolute inset-0 h-full w-full border-0",
              active ? "pointer-events-auto" : "pointer-events-none"
            )}
          />
        </div>
      ) : (
        <div
          className={cn(
            "flex h-full w-full items-center justify-center text-xs text-[var(--landing-muted)]",
            placeholderClassName
          )}
        >
          Chargement…
        </div>
      )}
    </div>
  )
}
