import { useEffect, useRef, useState } from 'preact/hooks';

// Cloudflare Turnstile integration.
//
// Rendering strategy: Turnstile injects its layout stylesheet into document.head,
// which does NOT cascade into our shadow DOM. When rendered inside our shadow DOM
// the iframe exists with correct attributes but paints as zero pixels because the
// wrapper Turnstile creates has no resolved styles. To work around this we mount
// Turnstile into a portal div appended to document.body (light DOM), then use
// getBoundingClientRect on the in-shadow placeholder to keep the portal visually
// overlaid on top of the captcha gate area.

type TurnstileOptions = {
    sitekey: string;
    callback?: (token: string) => void;
    'error-callback'?: () => void;
    'expired-callback'?: () => void;
    theme?: 'light' | 'dark' | 'auto';
    size?: 'normal' | 'compact' | 'flexible' | 'invisible';
    appearance?: 'always' | 'execute' | 'interaction-only';
};

declare global {
    interface Window {
        turnstile?: {
            render: (container: HTMLElement, opts: TurnstileOptions) => string;
            remove: (widgetId: string) => void;
            reset: (widgetId?: string) => void;
        };
        __helixTurnstileLoading?: Promise<void>;
    }
}

const SCRIPT_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';

export const loadTurnstile = (): Promise<void> => {
    if (typeof window === 'undefined') return Promise.resolve();
    if (window.turnstile) return Promise.resolve();
    if (window.__helixTurnstileLoading) return window.__helixTurnstileLoading;

    window.__helixTurnstileLoading = new Promise<void>((resolve, reject) => {
        const script = document.createElement('script');
        script.src = SCRIPT_URL;
        script.async = true;
        script.defer = true;
        script.onload = () => {
            const poll = () => {
                if (window.turnstile) resolve();
                else setTimeout(poll, 50);
            };
            poll();
        };
        script.onerror = () => reject(new Error('Turnstile failed to load'));
        document.head.appendChild(script);
    });
    return window.__helixTurnstileLoading;
};

type CaptchaProps = {
    siteKey: string;
    onToken: (token: string) => void;
    onError?: () => void;
};

export const Captcha = ({ siteKey, onToken, onError }: CaptchaProps) => {
    const placeholderRef = useRef<HTMLDivElement | null>(null);
    const portalRef = useRef<HTMLDivElement | null>(null);
    const widgetIdRef = useRef<string | null>(null);
    const onTokenRef = useRef(onToken);
    const onErrorRef = useRef(onError);
    const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading');

    onTokenRef.current = onToken;
    onErrorRef.current = onError;

    useEffect(() => {
        if (!siteKey || !placeholderRef.current) return;
        let cancelled = false;

        // Light-DOM portal so Turnstile's document.head styles actually apply.
        const portal = document.createElement('div');
        portal.setAttribute('data-helix-turnstile', '');
        portal.style.cssText = [
            'position:fixed',
            'z-index:2147483647',
            'width:300px',
            'height:65px',
            'pointer-events:auto',
        ].join(';');
        document.body.appendChild(portal);
        portalRef.current = portal;

        const updatePosition = () => {
            if (!placeholderRef.current || !portalRef.current) return;
            const rect = placeholderRef.current.getBoundingClientRect();
            portalRef.current.style.top = `${rect.top}px`;
            portalRef.current.style.left = `${rect.left}px`;
        };

        updatePosition();
        window.addEventListener('resize', updatePosition);
        window.addEventListener('scroll', updatePosition, true);

        // Reposition on animation frame while the gate is mounted, so the portal
        // tracks the placeholder through panel open animation and any layout shifts.
        let rafId = 0;
        const trackLoop = () => {
            updatePosition();
            rafId = requestAnimationFrame(trackLoop);
        };
        rafId = requestAnimationFrame(trackLoop);

        loadTurnstile()
            .then(() => {
                if (cancelled || !portalRef.current || !window.turnstile) return;
                try {
                    widgetIdRef.current = window.turnstile.render(portalRef.current, {
                        sitekey: siteKey,
                        callback: (token) => onTokenRef.current(token),
                        'error-callback': () => {
                            setStatus('error');
                            onErrorRef.current?.();
                        },
                        'expired-callback': () => onTokenRef.current(''),
                        theme: 'light',
                        size: 'normal',
                    });
                    setStatus('ready');
                } catch {
                    setStatus('error');
                    onErrorRef.current?.();
                }
            })
            .catch(() => {
                setStatus('error');
                onErrorRef.current?.();
            });

        return () => {
            cancelled = true;
            cancelAnimationFrame(rafId);
            window.removeEventListener('resize', updatePosition);
            window.removeEventListener('scroll', updatePosition, true);
            if (widgetIdRef.current && window.turnstile) {
                try {
                    window.turnstile.remove(widgetIdRef.current);
                } catch {
                    // ignore — widget may already be gone
                }
                widgetIdRef.current = null;
            }
            portal.remove();
            portalRef.current = null;
        };
    }, [siteKey]);

    return (
        <div class="widget-captcha">
            <div class="widget-captcha-mount" ref={placeholderRef} />
            {status === 'loading' && <div class="widget-captcha-status">Loading verification…</div>}
            {status === 'error' && <div class="widget-captcha-status widget-captcha-error">Verification failed to load. Please refresh.</div>}
        </div>
    );
};
