import React, {useEffect, useRef, useState} from 'react';
import {LoadingIndicator} from '@tryghost/shade/components';
import {cn} from '@tryghost/shade/utils';
import type {EmailPreviewFrameState} from './use-email-preview';

interface EmailPreviewFrameProps {
    previewState: EmailPreviewFrameState;
}

const EmailPreviewFrame: React.FC<EmailPreviewFrameProps> = ({previewState}) => {
    const [previewHeight, setPreviewHeight] = useState<number | null>(null);
    const [isPreviewReady, setIsPreviewReady] = useState(false);
    const isPreviewReadyRef = useRef(false);
    const previewIframeRef = useRef<HTMLIFrameElement>(null);
    const previewResizeObserverRef = useRef<ResizeObserver | null>(null);
    const previewMeasureFrameRef = useRef<number | null>(null);
    const previewRevealFrameRef = useRef<number | null>(null);

    function cleanupPreviewMeasurement() {
        previewResizeObserverRef.current?.disconnect();
        previewResizeObserverRef.current = null;

        if (previewMeasureFrameRef.current !== null) {
            window.cancelAnimationFrame(previewMeasureFrameRef.current);
            previewMeasureFrameRef.current = null;
        }

        if (previewRevealFrameRef.current !== null) {
            window.cancelAnimationFrame(previewRevealFrameRef.current);
            previewRevealFrameRef.current = null;
        }
    }

    const previewHtml = previewState.status === 'success' ? previewState.html : '';

    useEffect(() => {
        cleanupPreviewMeasurement();
        isPreviewReadyRef.current = false;
        setIsPreviewReady(false);
        setPreviewHeight(null);

        return () => {
            cleanupPreviewMeasurement();
        };
    }, [previewHtml, previewState.status]);

    function syncPreviewHeight() {
        const iframe = previewIframeRef.current;
        const doc = iframe?.contentDocument;

        if (!iframe || !doc) {
            return;
        }

        doc.documentElement.style.overflowY = 'hidden';
        doc.body.style.overflowY = 'hidden';

        const nextHeight = Math.max(
            doc.documentElement?.scrollHeight || 0,
            doc.body?.scrollHeight || 0,
            doc.documentElement?.offsetHeight || 0,
            doc.body?.offsetHeight || 0
        );

        if (nextHeight > 0) {
            setPreviewHeight(previousHeight => (previousHeight === nextHeight ? previousHeight : nextHeight));

            if (!isPreviewReadyRef.current && previewRevealFrameRef.current === null) {
                previewRevealFrameRef.current = window.requestAnimationFrame(() => {
                    previewRevealFrameRef.current = window.requestAnimationFrame(() => {
                        previewRevealFrameRef.current = null;
                        isPreviewReadyRef.current = true;
                        setIsPreviewReady(true);
                    });
                });
            }
        }
    }

    function queuePreviewHeightSync() {
        if (previewMeasureFrameRef.current !== null) {
            window.cancelAnimationFrame(previewMeasureFrameRef.current);
        }

        previewMeasureFrameRef.current = window.requestAnimationFrame(() => {
            previewMeasureFrameRef.current = null;
            syncPreviewHeight();
        });
    }

    function handlePreviewLoad() {
        const iframe = previewIframeRef.current;
        const doc = iframe?.contentDocument;

        if (!iframe || !doc) {
            return;
        }

        cleanupPreviewMeasurement();
        queuePreviewHeightSync();

        if (typeof ResizeObserver !== 'undefined') {
            const observer = new ResizeObserver(() => {
                queuePreviewHeightSync();
            });

            observer.observe(doc.documentElement);
            observer.observe(doc.body);
            previewResizeObserverRef.current = observer;
        }
    }

    const showPreviewLoading = previewState.status === 'loading' || (previewState.status === 'success' && !isPreviewReady);

    return (
        <div className='relative w-full' data-testid='email-preview'>
            {showPreviewLoading && (
                <div
                    className='flex min-h-full items-start justify-center pt-24'
                    data-testid='email-preview-loading'
                    style={previewHeight ? {height: `${previewHeight}px`} : undefined}
                >
                    <LoadingIndicator size='md' />
                </div>
            )}
            {previewState.status === 'success' && (
                <div
                    aria-hidden={!isPreviewReady}
                    className={cn(
                        'w-full',
                        !isPreviewReady && 'pointer-events-none absolute top-0 left-0 opacity-0'
                    )}
                >
                    {/* Keep the iframe hidden until it has been measured to avoid a visible resize jump. */}
                    <iframe
                        ref={previewIframeRef}
                        className='w-full rounded bg-white'
                        data-testid='email-preview-iframe'
                        sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
                        srcDoc={previewState.html}
                        style={{height: previewHeight ? `${previewHeight}px` : '600px'}}
                        title='Email preview'
                        onLoad={handlePreviewLoad}
                    />
                </div>
            )}
            {(previewState.status === 'error' || previewState.status === 'invalid') && (
                <div className='flex h-full items-center justify-center px-4' data-testid='email-preview-error'>
                    <span className='text-sm text-destructive'>{previewState.message}</span>
                </div>
            )}
        </div>
    );
};

export default EmailPreviewFrame;
