'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
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';
const VIEWPORT_WIDTHS = {
    desktop: '100%',
    tablet: '768px',
    mobile: '375px',
};
const PREVIEW_STREAM_PATH = '/api/cms/preview/stream';
function postToIframe(iframe, src, data) {
    if (!iframe?.contentWindow || !src)
        return;
    let targetOrigin;
    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, }) {
    const iframeRef = useRef(null);
    const [viewport, setViewport] = useState('desktop');
    const [loading, setLoading] = useState(true);
    const [previewSrc, setPreviewSrc] = useState(null);
    const [previewToken, setPreviewToken] = useState(null);
    const [streamStatus, setStreamStatus] = useState('idle');
    useEffect(() => {
        if (!documentId || !previewUrl) {
            setPreviewSrc(null);
            setPreviewToken(null);
            return;
        }
        let cancelled = false;
        async function fetchToken() {
            const res = await cmsApi('/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) => {
            try {
                const payload = JSON.parse(event.data);
                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 (_jsxs("div", { className: "border-border bg-muted flex h-full flex-col items-center justify-center rounded-lg border border-dashed p-8", children: [_jsx("p", { className: "text-muted-foreground text-center text-sm", children: !documentId
                        ? 'Save the document first to enable preview'
                        : 'Configure a preview URL in the collection settings to enable live preview' }), _jsx("button", { onClick: onClose, className: "text-muted-foreground hover:text-muted-foreground mt-4 text-xs", children: "Close Preview" })] }));
    }
    return (_jsxs("div", { className: "border-border bg-card flex h-full flex-col border-l", children: [_jsxs("div", { className: "border-border bg-muted flex items-center justify-between border-b px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-1", children: [[
                                ['desktop', Monitor],
                                ['tablet', Tablet],
                                ['mobile', Smartphone],
                            ].map(([vp, Icon]) => (_jsx("button", { onClick: () => setViewport(vp), className: `rounded p-1.5 ${viewport === vp ? 'bg-card text-primary shadow-sm' : 'text-muted-foreground hover:text-muted-foreground'}`, title: vp, children: _jsx(Icon, { className: "h-4 w-4" }) }, vp))), _jsx("span", { className: "bg-card text-muted-foreground ml-2 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium", 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.', children: streamStatus === 'connected' ? (_jsxs(_Fragment, { children: [_jsx(Wifi, { className: "text-success h-3 w-3", "aria-hidden": true }), " Live"] })) : streamStatus === 'connecting' ? (_jsxs(_Fragment, { children: [_jsx(Wifi, { className: "text-info h-3 w-3 animate-pulse", "aria-hidden": true }), " Connecting"] })) : streamStatus === 'offline' ? (_jsxs(_Fragment, { children: [_jsx(WifiOff, { className: "text-warning h-3 w-3", "aria-hidden": true }), " Reconnecting"] })) : (_jsxs(_Fragment, { children: [_jsx(WifiOff, { className: "text-muted-foreground h-3 w-3", "aria-hidden": true }), " Idle"] })) })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: handleRefresh, className: "text-muted-foreground hover:text-muted-foreground rounded p-1.5", title: "Refresh", children: _jsx(RefreshCw, { className: "h-4 w-4" }) }), _jsx("button", { onClick: handleOpenExternal, className: "text-muted-foreground hover:text-muted-foreground rounded p-1.5", title: "Open in new tab", children: _jsx(ExternalLink, { className: "h-4 w-4" }) }), _jsx("button", { onClick: onClose, className: "text-muted-foreground hover:text-muted-foreground rounded p-1.5", title: "Close", children: _jsx(X, { className: "h-4 w-4" }) })] })] }), _jsx("div", { className: "bg-muted flex flex-1 justify-center overflow-auto p-4", children: _jsxs("div", { style: { width: VIEWPORT_WIDTHS[viewport], maxWidth: '100%', transition: 'width 0.3s' }, className: "relative", children: [loading && (_jsx("div", { className: "bg-card/80 absolute inset-0 z-10 flex items-center justify-center rounded-lg", children: _jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600" }) })), _jsx("iframe", { ref: iframeRef, src: previewSrc, className: "border-border bg-card h-full w-full rounded-lg border shadow-lg", style: { minHeight: '600px' }, onLoad: () => setLoading(false), title: "Page Preview" })] }) })] }));
}
//# sourceMappingURL=LivePreview.js.map