import { useMemo, useRef } from "react";

import { extendBannerBodyStylesheet } from "@devowl-wp/web-cookie-banner";
import type { ButtonFunctionality } from "@devowl-wp/web-cookie-banner";

import { useBanner } from "../../../contexts/banner.js";
import { useBannerButtonCallbacks } from "../../../hooks/banner/useBannerButtonCallbacks.js";
import { useBannerStylesheet } from "../../../hooks/banner/useBannerStylesheet.js";
import { Button } from "../../common/button.js";

import type { FC, ReactNode } from "react";

/**
 * Randomizes button order to avoid detection by ad-blockers.
 */
const RandomOrder: FC<{
    children: ReactNode[];
    enabled: boolean;
}> = ({ children, enabled }) => {
    if (!enabled) {
        return <>{children}</>;
    }
    const shuffledChildren = [...children].sort(() => Math.random() - 0.5);
    return <>{shuffledChildren}</>;
};

const BannerButtonList: FC = () => {
    const banner = useBanner();
    const {
        isScreenReader,
        isConsentRecord,
        activeAction,
        bodyDesign: { acceptEssentialsUseAcceptAll, acceptAllOneRowLayout },
        decision: {
            showGroups,
            groupsFirstView,
            saveButton,
            acceptAll,
            acceptEssentials,
            buttonOrder: buttonOrderString,
        },
        texts: {
            acceptAll: acceptAllText,
            acceptEssentials: acceptEssentialsText,
            acceptIndividual: acceptIndividualText,
        },
        saveButton: { type: saveButtonType, useAcceptAll: saveButtonUseAcceptAll },
        individualTexts: { save },
        individualPrivacyOpen,
        didGroupFirstChange,
        productionNotice,
        buttonClicked = "",
        fetchLazyLoadedDataForSecondView,
    } = banner;
    const {
        a11yIds: { firstButton },
    } = useBannerStylesheet();
    const { buttonOrderClasses } = useBannerStylesheet().extend(...extendBannerBodyStylesheet);

    const useAcceptEssentialsUseAcceptAll = acceptEssentialsUseAcceptAll && acceptAll === acceptEssentials;
    const useSaveButtonUseAcceptAll = saveButtonUseAcceptAll && acceptAll === saveButtonType;

    // Calculate order of the buttons depending on a string like `all,essential,save,individual`
    const {
        all: buttonOrderAll,
        essential: buttonOrderEssential,
        individual: buttonOrderIndividual,
        save: buttonOrderSave,
    } = useMemo(() => {
        const buttonOrder = buttonOrderString.split(",") as ButtonFunctionality[];
        const buttonToOrder = buttonOrder.reduce(
            (previous, curr) => {
                previous[curr] = buttonOrder.indexOf(curr);
                return previous;
            },
            {} as Record<ButtonFunctionality, number>,
        );
        const orderToButton = buttonOrder.reduce(
            (previous, curr) => {
                previous[buttonOrder.indexOf(curr)] = curr;
                return previous;
            },
            {} as Record<number, ButtonFunctionality>,
        );

        // If one-row layout is enabled, reverse the first two orders so the first button gets moved to the right
        if (acceptAllOneRowLayout) {
            buttonToOrder[orderToButton[0]] = 1;
            buttonToOrder[orderToButton[1]] = 0;
        }

        return buttonToOrder;
    }, [buttonOrderString, acceptAllOneRowLayout]);

    const isPro = process.env.PLUGIN_CTX === "pro";
    const {
        buttonClickedAll,
        buttonClickedEssentials,
        buttonClickedCustom,
        acceptAll: handleAll,
        acceptEssentials: handleEssentials,
        acceptIndividual: handleIndividual,
        openIndividualPrivacy,
    } = useBannerButtonCallbacks();

    // We expect a reload of the page for the "change" action (keeps also dialog open)
    const busyOnClick = activeAction === "change" && !isConsentRecord;
    const groupsFirstViewEnabled = showGroups && groupsFirstView;

    // Calculate button visibility
    const showSaveButtonInsteadOfAcceptAll =
        !individualPrivacyOpen &&
        isPro &&
        groupsFirstViewEnabled &&
        saveButton === "afterChangeAll" &&
        didGroupFirstChange;
    const showStandaloneSaveButton =
        individualPrivacyOpen ||
        (isPro &&
            groupsFirstViewEnabled &&
            (saveButton === "always" || (saveButton === "afterChange" && didGroupFirstChange)));
    const showIndividual = !individualPrivacyOpen;

    const fetchLazyLoadedDataForSecondViewTimeout = useRef<ReturnType<typeof setTimeout>>();

    return (
        <RandomOrder enabled={!isScreenReader}>
            {showSaveButtonInsteadOfAcceptAll ? (
                <Button
                    onClick={handleIndividual}
                    busyOnClick={busyOnClick}
                    className={buttonOrderClasses[buttonOrderAll][1]}
                    type="acceptAll"
                    framed={buttonClicked === buttonClickedCustom}
                    id={firstButton}
                >
                    {save}
                </Button>
            ) : (
                <Button
                    onClick={handleAll}
                    busyOnClick={busyOnClick}
                    className={buttonOrderClasses[buttonOrderAll][1]}
                    type="acceptAll"
                    framed={buttonClicked === buttonClickedAll}
                    id={firstButton}
                >
                    {acceptAllText}
                </Button>
            )}
            <Button
                onClick={() => handleEssentials()}
                busyOnClick={busyOnClick}
                className={buttonOrderClasses[buttonOrderEssential][1]}
                type={useAcceptEssentialsUseAcceptAll ? "acceptAll" : "acceptEssentials"}
                framed={buttonClicked === buttonClickedEssentials}
            >
                {acceptEssentialsText}
            </Button>
            {showStandaloneSaveButton && (
                <Button
                    onClick={handleIndividual}
                    busyOnClick={busyOnClick}
                    className={buttonOrderClasses[buttonOrderSave][1]}
                    type={useSaveButtonUseAcceptAll ? "acceptAll" : "save"}
                    framed={buttonClicked === buttonClickedCustom}
                >
                    {save}
                </Button>
            )}
            {showIndividual && (
                <Button
                    onClick={openIndividualPrivacy}
                    onMouseEnter={() => {
                        // Preload the second view data on hover
                        if (fetchLazyLoadedDataForSecondView) {
                            fetchLazyLoadedDataForSecondViewTimeout.current = setTimeout(
                                fetchLazyLoadedDataForSecondView,
                                500,
                            );
                        }
                    }}
                    onMouseLeave={() => clearTimeout(fetchLazyLoadedDataForSecondViewTimeout.current)}
                    busyOnClick={busyOnClick}
                    className={buttonOrderClasses[buttonOrderIndividual][1]}
                    type="acceptIndividual"
                    framed={buttonClicked.startsWith("ind_")}
                >
                    {acceptIndividualText}
                </Button>
            )}
            {productionNotice}
        </RandomOrder>
    );
};

export { BannerButtonList };
