import {useCallback, useEffect, useRef} from '@wordpress/element';

const MOBILE_THEME_BG_COLORS = {
    light: '#fff',
    dark: '#121313',
};
const LOCK_DELAY_MS = 300;
const BREAKPOINT_MOBILE = 767.98;

const useMobileChatLock = ({getActiveThemeVariant}) => {
    const isMobileBodyLocked = useRef(false);
    const bodyOriginalStyles = useRef(new Map());
    const htmlOriginalStyles = useRef(new Map());
    const themeObserver = useRef(null);
    const hasOpenedRef = useRef(false);
    const scrollPositionRef = useRef({x: 0, y: 0});
    const lockTimeoutRef = useRef(null);

    const setInlineStyle = useCallback((element, stylesRef, property, value, priority = '') => {
        if (!element || !element.style) {
            return;
        }
        if (!stylesRef.current.has(property)) {
            stylesRef.current.set(property, {
                value: element.style.getPropertyValue(property),
                priority: element.style.getPropertyPriority(property),
            });
        }
        element.style.setProperty(property, value, priority);
    }, []);

    const restoreInlineStyles = useCallback((element, stylesRef) => {
        if (!element || !element.style) {
            const previousStyles = new Map(stylesRef.current);
            stylesRef.current.clear();
            return previousStyles;
        }
        const previousStyles = new Map(stylesRef.current);
        stylesRef.current.forEach(({value, priority}, property) => {
            if (value) {
                element.style.setProperty(property, value, priority);
            } else {
                element.style.removeProperty(property);
            }
        });
        stylesRef.current.clear();
        return previousStyles;
    }, []);

    const applyMobileChatLock = useCallback((backgroundColor) => {
        if (typeof document === 'undefined') {
            return;
        }
        const {body, documentElement: html} = document;
        if (!body || !html) {
            return;
        }
        if (!isMobileBodyLocked.current) {
            scrollPositionRef.current = {
                x: window.pageXOffset || window.scrollX || 0,
                y: window.pageYOffset || window.scrollY || 0,
            };
            setInlineStyle(body, bodyOriginalStyles, 'overflow', 'hidden');
            setInlineStyle(html, htmlOriginalStyles, 'position', 'fixed', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'top', '0', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'left', '0', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'overscroll-behavior', 'none', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'width', '0', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'height', '0', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'margin', '0', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'overflow', 'hidden', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'overflow-y', 'hidden', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'overflow-x', 'hidden', 'important');
            setInlineStyle(html, htmlOriginalStyles, 'transform', 'none', 'important');
            isMobileBodyLocked.current = true;
        }
        if (backgroundColor) {
            setInlineStyle(body, bodyOriginalStyles, 'background-color', backgroundColor);
        }
    }, [setInlineStyle]);

    const releaseMobileChatLock = useCallback(() => {
        if (lockTimeoutRef.current) {
            clearTimeout(lockTimeoutRef.current);
            lockTimeoutRef.current = null;
        }
        hasOpenedRef.current = false;
        if (typeof document === 'undefined') {
            return;
        }
        if (!isMobileBodyLocked.current && bodyOriginalStyles.current.size === 0 && htmlOriginalStyles.current.size === 0) {
            return;
        }
        const {body, documentElement: html} = document;
        const bodyPreviousStyles = restoreInlineStyles(body, bodyOriginalStyles);
        const htmlPreviousStyles = restoreInlineStyles(html, htmlOriginalStyles);

        ['overflow', 'overflow-y', 'overflow-x'].forEach(property => {
            if (!bodyPreviousStyles.has(property) || !bodyPreviousStyles.get(property).value) {
                body.style.removeProperty(property);
            }
            if (!htmlPreviousStyles.has(property) || !htmlPreviousStyles.get(property).value) {
                html.style.removeProperty(property);
            }
        });
        isMobileBodyLocked.current = false;
        if (typeof window !== 'undefined' && typeof document !== 'undefined') {
            const {x, y} = scrollPositionRef.current;
            const docEl = document.documentElement;
            const body = document.body;
            const docPrevScrollBehavior = docEl?.style?.scrollBehavior;
            const bodyPrevScrollBehavior = body?.style?.scrollBehavior;

            if (docEl) {
                docEl.style.scrollBehavior = 'auto';
            }
            if (body) {
                body.style.scrollBehavior = 'auto';
            }

            if (typeof window.scrollTo === 'function') {
                window.scrollTo(x, y);
            } else {
                if (docEl) {
                    docEl.scrollTop = y;
                    docEl.scrollLeft = x;
                }
                if (body) {
                    body.scrollTop = y;
                    body.scrollLeft = x;
                }
            }

            if (docEl) {
                if (docPrevScrollBehavior) {
                    docEl.style.scrollBehavior = docPrevScrollBehavior;
                } else {
                    docEl.style.removeProperty('scroll-behavior');
                }
            }
            if (body) {
                if (bodyPrevScrollBehavior) {
                    body.style.scrollBehavior = bodyPrevScrollBehavior;
                } else {
                    body.style.removeProperty('scroll-behavior');
                }
            }
        }
    }, [restoreInlineStyles]);

    const refreshMobileBodyLock = useCallback(() => {
        if (typeof window === 'undefined') {
            return;
        }

        const shouldLock = window.innerWidth < BREAKPOINT_MOBILE && hasOpenedRef.current;

        if (shouldLock) {
            const runLock = () => {
                const themeVariant = typeof getActiveThemeVariant === 'function' ? getActiveThemeVariant() : null;
                const backgroundColor = MOBILE_THEME_BG_COLORS[themeVariant] || MOBILE_THEME_BG_COLORS.light;
                applyMobileChatLock(backgroundColor);
            };

            if (isMobileBodyLocked.current) {
                runLock();
            } else {
                if (lockTimeoutRef.current) {
                    clearTimeout(lockTimeoutRef.current);
                }
                lockTimeoutRef.current = setTimeout(() => {
                    lockTimeoutRef.current = null;
                    if (!hasOpenedRef.current || typeof window === 'undefined' || window.innerWidth >= BREAKPOINT_MOBILE) {
                        return;
                    }
                    runLock();
                }, LOCK_DELAY_MS);
            }
        } else {
            releaseMobileChatLock();
        }
    }, [applyMobileChatLock, getActiveThemeVariant, releaseMobileChatLock]);

    const setMobileLockState = useCallback((hasOpened) => {
        const targetState = !!hasOpened;
        hasOpenedRef.current = targetState;
        if (targetState) {
            refreshMobileBodyLock();
        } else {
            if (lockTimeoutRef.current) {
                clearTimeout(lockTimeoutRef.current);
                lockTimeoutRef.current = null;
            }
            releaseMobileChatLock();
        }
    }, [refreshMobileBodyLock, releaseMobileChatLock]);

    useEffect(() => {
        refreshMobileBodyLock();
    }, [refreshMobileBodyLock]);

    useEffect(() => {
        if (typeof window === 'undefined') {
            return undefined;
        }
        window.addEventListener('resize', refreshMobileBodyLock);
        return () => {
            window.removeEventListener('resize', refreshMobileBodyLock);
            releaseMobileChatLock();
        };
    }, [refreshMobileBodyLock, releaseMobileChatLock]);

    useEffect(() => {
        if (typeof MutationObserver === 'undefined' || typeof document === 'undefined') {
            return undefined;
        }
        if (themeObserver.current) {
            themeObserver.current.disconnect();
        }
        const observer = new MutationObserver(() => {
            refreshMobileBodyLock();
        });
        const target = document.getElementById('lbaic-chatbot');
        if (target) {
            observer.observe(target, {
                subtree: true,
                attributes: true,
                attributeFilter: ['class']
            });
            themeObserver.current = observer;
        }

        return () => {
            observer.disconnect();
            if (themeObserver.current === observer) {
                themeObserver.current = null;
            }
        };
    }, [refreshMobileBodyLock]);

    return {
        refreshMobileBodyLock,
        releaseMobileChatLock,
        setMobileLockState,
    };
};

export default useMobileChatLock;


