import { useRect } from "@reach/rect";
import { Fragment, Suspense, useCallback, useEffect, useRef, useState } from "react";

import { HTML_ATTRIBUTE_HERO_DIALOG_DEFAULT_OPEN } from "@devowl-wp/headless-content-unblocker";
import { extendBlockerHeroStylesheet, extendCommonButtonsStylesheet } from "@devowl-wp/web-cookie-banner";

import { useBlocker } from "../../../contexts/blocker.js";
import { useBlockerStylesheet } from "../../../hooks/blocker/useBlockerStylesheet.js";
import { CloseIcon } from "../../closeIcon.js";
import { Portal } from "../../portal.js";
import { BlockerTextContainer } from "../textContainer.js";

import type { DOMAttributes, FC, FocusEvent, MutableRefObject } from "react";

const BlockerHeroDialog: FC<{
    blockerClassName: string;
    blockerOverlayId: string;
    heroContainerRef: MutableRefObject<HTMLElement>;
    fixed?: boolean;
}> = ({ blockerClassName, blockerOverlayId, heroContainerRef: ref, fixed }) => {
    const stylesheet = useBlockerStylesheet();
    const { HeroOverlay, HeroOverlayBlocker, A11ySkipToLink, screenReaderOnlyClass, fixedDialog } = stylesheet
        .extend(...extendBlockerHeroStylesheet)
        .extend(...extendCommonButtonsStylesheet);
    const blocker = useBlocker();
    const {
        headerDesign: { fontSize, fontColor },
        i18n: { close },
        blockedNode,
    } = blocker;
    const refLastActiveElement = useRef<HTMLElement>();
    const [isDefaultBlockerVisible, setIsDefaultBlockerVisible] = useState(
        !!blockedNode?.hasAttribute(HTML_ATTRIBUTE_HERO_DIALOG_DEFAULT_OPEN),
    );
    const rect = useRect(ref, { observe: isDefaultBlockerVisible });
    const overlayRef = useRef<HTMLDivElement>();

    // Automatically close on outside click
    const handleOutsideClick: DOMAttributes<HTMLElement>["onClick"] = useCallback(
        (e) => {
            if (
                isDefaultBlockerVisible &&
                [overlayRef.current, overlayRef.current?.nextElementSibling].indexOf(e.target as HTMLDivElement) > -1
            ) {
                setIsDefaultBlockerVisible(false);
            }
        },
        [isDefaultBlockerVisible, overlayRef.current],
    );

    const handleAcessibilityClose = (e: FocusEvent<HTMLAnchorElement, Element>) => {
        // Accessibility, hide hero container and focus previously selected element
        e.preventDefault();
        setIsDefaultBlockerVisible(false);
        refLastActiveElement.current?.focus();
    };

    useEffect(() => {
        if (ref.current) {
            const listener = (e: MouseEvent) => {
                refLastActiveElement.current = document.activeElement as HTMLElement;
                const focusSkipToConsentChoices = (e.target as HTMLElement).classList.contains(screenReaderOnlyClass);

                // Save reference in data of hero container ref, so we can delegate the click for `confirm()`, see also `delegateClick()`
                if (ref.current) {
                    ref.current.consentDelegateClick = {
                        element: refLastActiveElement.current,
                    };
                }

                setIsDefaultBlockerVisible(true);
                setTimeout(() => {
                    if (focusSkipToConsentChoices) {
                        (
                            overlayRef.current?.nextElementSibling.querySelector(`a[href^="#a"]`) as HTMLAnchorElement
                        ).focus();
                    }
                }, 50);

                e.preventDefault();
                e.stopImmediatePropagation();
                return false;
            };
            ref.current.addEventListener("click", listener, true);
            return () => ref.current?.removeEventListener("click", listener, true);
        }

        return () => {
            // Silence is golden.
        };
    }, [ref.current]);

    return isDefaultBlockerVisible && rect ? (
        <Portal renderInContainer={document.body}>
            <Fragment>
                <HeroOverlay ref={overlayRef} onClick={handleOutsideClick} />
                <HeroOverlayBlocker
                    id={blockerOverlayId}
                    rectLeft={rect.left + window.scrollX}
                    rectTop={rect.top + window.scrollY}
                    rectWidth={rect.width}
                    className={`${blockerClassName} ${fixed ? fixedDialog : ""}`}
                    onClick={handleOutsideClick}
                    interaction-player-uqid={isDefaultBlockerVisible ? "blocker" : undefined}
                >
                    <A11ySkipToLink href="#" onFocus={handleAcessibilityClose}>
                        &nbsp;
                    </A11ySkipToLink>
                    <Suspense fallback={null}>
                        <BlockerTextContainer
                            closeIcon={
                                <CloseIcon
                                    tooltipText={close}
                                    width={fontSize}
                                    color={fontColor}
                                    thickness={2}
                                    onClick={() => setIsDefaultBlockerVisible(false)}
                                />
                            }
                        />
                    </Suspense>
                    <A11ySkipToLink href="#" onFocus={handleAcessibilityClose}>
                        &nbsp;
                    </A11ySkipToLink>
                </HeroOverlayBlocker>
            </Fragment>
        </Portal>
    ) : null;
};

export { BlockerHeroDialog };
