'use client'

import { useState, useRef, useEffect, useCallback } from 'react'
import {
  Monitor,
  Tablet,
  Smartphone,
  RefreshCw,
  ExternalLink,
  X,
  Wifi,
  WifiOff,
} from 'lucide-react'
import { cmsApi } from '../lib/api.js'

interface LivePreviewProps {
  collection: string
  documentId?: string
  previewUrl?: string
  values: Record<string, unknown>
  onClose: () => void
}

type Viewport = 'desktop' | 'tablet' | 'mobile'
type StreamStatus = 'idle' | 'connecting' | 'connected' | 'offline'

const VIEWPORT_WIDTHS: Record<Viewport, string> = {
  desktop: '100%',
  tablet: '768px',
  mobile: '375px',
}

const PREVIEW_STREAM_PATH = '/api/cms/preview/stream'

function postToIframe(
  iframe: HTMLIFrameElement | null,
  src: string | null,
  data: Record<string, unknown>,
): void {
  if (!iframe?.contentWindow || !src) return
  let targetOrigin: string
  try {
    targetOrigin = new URL(src).origin
  } catch {
    targetOrigin = window.location.origin
  }
  iframe.contentWindow.postMessage({ type: 'actuate-preview-update', data }, targetOrigin)
}

export function LivePreview({
  collection,
  documentId,
  previewUrl,
  values,
  onClose,
}: LivePreviewProps) {
  const iframeRef = useRef<HTMLIFrameElement>(null)
  const [viewport, setViewport] = useState<Viewport>('desktop')
  const [loading, setLoading] = useState(true)
  const [previewSrc, setPreviewSrc] = useState<string | null>(null)
  const [previewToken, setPreviewToken] = useState<string | null>(null)
  const [streamStatus, setStreamStatus] = useState<StreamStatus>('idle')

  useEffect(() => {
    if (!documentId || !previewUrl) {
      setPreviewSrc(null)
      setPreviewToken(null)
      return
    }

    let cancelled = false

    async function fetchToken() {
      const res = await cmsApi<{ token: string }>('/preview/token', {
        method: 'POST',
        body: JSON.stringify({ collection, documentId }),
      })
      if (cancelled) return
      if (res.data?.token) {
        const sep = previewUrl!.includes('?') ? '&' : '?'
        setPreviewToken(res.data.token)
        setPreviewSrc(`${previewUrl}${sep}preview=true#token=${res.data.token}`)
      }
    }

    fetchToken()
    return () => {
      cancelled = true
    }
  }, [collection, documentId, previewUrl])

  useEffect(() => {
    postToIframe(iframeRef.current, previewSrc, values)
  }, [values, previewSrc])

  /**
   * SSE pipe — when the server pushes a draft update for the same
   * `{collection, documentId}`, forward the new `values` straight to the
   * iframe via `postMessage`. The bus key matches the token's payload, so
   * a second admin session updating the same draft (e.g. an AI agent)
   * appears live in this preview without polling.
   */
  useEffect(() => {
    if (typeof window === 'undefined' || typeof EventSource === 'undefined') return
    if (!documentId || !previewToken) {
      setStreamStatus('idle')
      return
    }
    setStreamStatus('connecting')
    const source = new EventSource(
      `${PREVIEW_STREAM_PATH}?token=${encodeURIComponent(previewToken)}`,
      { withCredentials: true },
    )

    const onReady = () => setStreamStatus('connected')
    const onUpdate = (event: MessageEvent<string>) => {
      try {
        const payload = JSON.parse(event.data) as { values?: Record<string, unknown> }
        if (payload.values && typeof payload.values === 'object') {
          postToIframe(iframeRef.current, previewSrc, payload.values)
        }
      } catch {
        // Ignore malformed events — the SSE wire format guarantees JSON,
        // but a future schema bump shouldn't break this consumer.
      }
    }
    const onError = () => setStreamStatus('offline')
    const onOpen = () => setStreamStatus((s) => (s === 'offline' ? 'connecting' : s))

    source.addEventListener('ready', onReady)
    source.addEventListener('update', onUpdate)
    source.addEventListener('error', onError)
    source.addEventListener('open', onOpen)

    return () => {
      source.removeEventListener('ready', onReady)
      source.removeEventListener('update', onUpdate)
      source.removeEventListener('error', onError)
      source.removeEventListener('open', onOpen)
      source.close()
      setStreamStatus('idle')
    }
  }, [documentId, previewToken, previewSrc])

  const handleRefresh = useCallback(() => {
    if (iframeRef.current) {
      setLoading(true)
      iframeRef.current.src = iframeRef.current.src
    }
  }, [])

  const handleOpenExternal = useCallback(() => {
    if (previewSrc) window.open(previewSrc, '_blank')
  }, [previewSrc])

  if (!previewSrc) {
    return (
      <div className="flex h-full flex-col items-center justify-center rounded-lg border border-dashed border-gray-300 bg-gray-50 p-8">
        <p className="text-center text-sm text-gray-500">
          {!documentId
            ? 'Save the document first to enable preview'
            : 'Configure a preview URL in the collection settings to enable live preview'}
        </p>
        <button onClick={onClose} className="mt-4 text-xs text-gray-400 hover:text-gray-600">
          Close Preview
        </button>
      </div>
    )
  }

  return (
    <div className="flex h-full flex-col border-l border-gray-200 bg-white">
      <div className="flex items-center justify-between border-b border-gray-200 bg-gray-50 px-3 py-2">
        <div className="flex items-center gap-1">
          {(
            [
              ['desktop', Monitor],
              ['tablet', Tablet],
              ['mobile', Smartphone],
            ] as const
          ).map(([vp, Icon]) => (
            <button
              key={vp}
              onClick={() => setViewport(vp)}
              className={`rounded p-1.5 ${viewport === vp ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-400 hover:text-gray-600'}`}
              title={vp}
            >
              <Icon className="h-4 w-4" />
            </button>
          ))}
          <span
            className="ml-2 inline-flex items-center gap-1 rounded-full bg-white px-2 py-0.5 text-[10px] font-medium text-gray-600"
            title={
              streamStatus === 'connected'
                ? 'Live preview is streaming updates from the server.'
                : streamStatus === 'connecting'
                  ? 'Connecting to the live preview stream…'
                  : streamStatus === 'offline'
                    ? 'Live stream disconnected. Updates from this admin still work; cross-session updates will reconnect automatically.'
                    : 'Live preview stream idle.'
            }
          >
            {streamStatus === 'connected' ? (
              <>
                <Wifi className="h-3 w-3 text-green-600" aria-hidden /> Live
              </>
            ) : streamStatus === 'connecting' ? (
              <>
                <Wifi className="h-3 w-3 animate-pulse text-blue-500" aria-hidden /> Connecting
              </>
            ) : streamStatus === 'offline' ? (
              <>
                <WifiOff className="h-3 w-3 text-amber-500" aria-hidden /> Reconnecting
              </>
            ) : (
              <>
                <WifiOff className="h-3 w-3 text-gray-400" aria-hidden /> Idle
              </>
            )}
          </span>
        </div>
        <div className="flex items-center gap-1">
          <button
            onClick={handleRefresh}
            className="rounded p-1.5 text-gray-400 hover:text-gray-600"
            title="Refresh"
          >
            <RefreshCw className="h-4 w-4" />
          </button>
          <button
            onClick={handleOpenExternal}
            className="rounded p-1.5 text-gray-400 hover:text-gray-600"
            title="Open in new tab"
          >
            <ExternalLink className="h-4 w-4" />
          </button>
          <button
            onClick={onClose}
            className="rounded p-1.5 text-gray-400 hover:text-gray-600"
            title="Close"
          >
            <X className="h-4 w-4" />
          </button>
        </div>
      </div>

      <div className="flex flex-1 justify-center overflow-auto bg-gray-100 p-4">
        <div
          style={{ width: VIEWPORT_WIDTHS[viewport], maxWidth: '100%', transition: 'width 0.3s' }}
          className="relative"
        >
          {loading && (
            <div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-white/80">
              <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600" />
            </div>
          )}
          <iframe
            ref={iframeRef}
            src={previewSrc}
            className="h-full w-full rounded-lg border border-gray-200 bg-white shadow-lg"
            style={{ minHeight: '600px' }}
            onLoad={() => setLoading(false)}
            title="Page Preview"
          />
        </div>
      </div>
    </div>
  )
}
