import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2007-2026 GoodData Corporation
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import cx from "classnames";
import { differenceInCalendarDays, differenceInMonths, format } from "date-fns";
import { debounce } from "lodash-es";
import { FormattedMessage, defineMessage, defineMessages, useIntl } from "react-intl";
import { v4 as uuid } from "uuid";
import { withTheme } from "@gooddata/sdk-ui-theme-provider";
import { Icon } from "../Icon/Icon.js";
import { Overlay } from "../Overlay/Overlay.js";
import { Typography } from "../Typography/Typography.js";
import { removeFromDom } from "../utils/domUtilities.js";
import { addCssToStylesheet } from "./addCssToStylesheet.js";
import { getItemActiveColor, getItemHoverColor, getSeparatorColor, getTextColor, getWorkspacePickerHoverColor, } from "./colors.js";
import { LOGOUT_MENU_ITEM_ID } from "./generateHeaderAccountMenuItems.js";
import { HeaderAccount } from "./HeaderAccount.js";
import { HeaderChatButton } from "./HeaderChatButton.js";
import { HeaderHelp } from "./HeaderHelp.js";
import { HeaderMenu } from "./HeaderMenu.js";
import { HeaderSearchButton } from "./HeaderSearchButton.js";
import { HeaderSearchProvider } from "./headerSearchContext.js";
import { HeaderUpsellButton } from "./HeaderUpsellButton.js";
function getOuterWidth(element) {
    const width = element.offsetWidth;
    const { marginLeft, marginRight } = getComputedStyle(element);
    return width + parseInt(marginLeft, 10) + parseInt(marginRight, 10);
}
function getWidthOfChildren(element, selector = "> *") {
    const SAFETY_PADDING = 10;
    return Array.from(element.querySelectorAll(selector))
        .map((el) => getOuterWidth(el))
        .reduce((sum, childWidth) => sum + childWidth, SAFETY_PADDING);
}
const messages = defineMessages({
    aiChatMobile: { id: "gs.header.ai.mobile" },
    aiChat: { id: "gs.header.ai" },
    search: { id: "gs.header.search" },
    notifications: { id: "gs.header.notifications" },
});
const HEADER_HELP_MENU_ITEM_ID = defineMessage({ id: "gs.header.help" }).id;
/**
 * @internal
 */
export const AppHeader = withTheme(function AppHeader({ logoHref = "/", accountMenuItems = [], helpMenuItems = [], menuItemsGroups = [], search, notificationsPanel, workspacePicker, isAccessibilityCompliant, logoUrl, logoTitle, organizationName, className, activeColor, headerColor, headerTextColor, documentationUrl, expiredDate, showUpsellButton, onUpsellButtonClick, badges, showStaticHelpMenu, userName, theme, helpMenuDropdownAlignPoints: helpDropdownAlign, disableHelpDropdown, onHelpClick, helpRedirectUrl, showChatItem, onChatItemClick, onLogoClick, onMenuItemClick, }) {
    const intl = useIntl();
    const [state, setState] = useState({
        childrenWidth: 0,
        guid: `header-${uuid()}`,
        isOverlayMenuOpen: false,
        responsiveMode: false,
        isHelpMenuOpen: false,
        isSearchMenuOpen: false,
        isNotificationsMenuOpen: false,
    });
    const nodeRef = useRef(null);
    const stylesheetRef = useRef(null);
    const measureChildren = useCallback(() => {
        const currentDOMNode = nodeRef.current;
        if (!currentDOMNode) {
            return;
        }
        const childrenWidth = getWidthOfChildren(currentDOMNode, ".gd-header-measure");
        setState((prevState) => {
            // When responsive mode is active, the header DOM no longer contains the full set of
            // elements used for width measurement (e.g. horizontal menu sections), so updating the
            // measured width would be incorrect and could lead to mode thrashing.
            if (prevState.responsiveMode) {
                return prevState;
            }
            if (prevState.childrenWidth === childrenWidth) {
                return prevState;
            }
            return { ...prevState, childrenWidth };
        });
    }, []);
    useEffect(() => {
        // Re-measure the header content width whenever the rendered header content changes.
        //
        // This is important for apps that load header menu items/workspace picker content
        // asynchronously after the header is mounted (e.g. permissions-driven menus).
        if (!state.responsiveMode) {
            measureChildren();
        }
    }, [
        measureChildren,
        state.responsiveMode,
        menuItemsGroups,
        accountMenuItems,
        helpMenuItems,
        search,
        notificationsPanel,
        badges,
        showChatItem,
        showUpsellButton,
        expiredDate,
        userName,
        documentationUrl,
        helpRedirectUrl,
        disableHelpDropdown,
    ]);
    const measure = useCallback(() => {
        const currentDOMNode = nodeRef.current;
        if (!currentDOMNode) {
            // ref is null because 'this.measure()' is called after 100ms 'componentWillUnmount' called,
            // which cleans the nodeRef
            return;
        }
        const currentWidth = currentDOMNode.clientWidth;
        const responsiveMode = currentWidth < state.childrenWidth;
        if (state.responsiveMode !== responsiveMode) {
            setState((prevState) => ({
                ...prevState,
                responsiveMode,
                isOverlayMenuOpen: false,
                isHelpMenuOpen: false,
                isSearchMenuOpen: false,
                isNotificationsMenuOpen: false,
            }));
        }
    }, [state.childrenWidth, state.responsiveMode]);
    const resizeHandler = useMemo(() => debounce(() => measure(), 100), [measure]);
    useEffect(() => {
        measure();
    }, [state.childrenWidth, measure]);
    useEffect(() => {
        window.addEventListener("resize", resizeHandler);
        return () => {
            window.removeEventListener("resize", resizeHandler);
            if (stylesheetRef.current) {
                removeFromDom(stylesheetRef.current);
            }
        };
    }, [resizeHandler]);
    const createStyles = useCallback(() => {
        const { guid } = state;
        const textColor = getTextColor(headerTextColor ?? "", headerColor ?? "");
        const itemActiveColor = getItemActiveColor(activeColor ?? "", headerColor ?? "");
        const itemHoverColor = getItemHoverColor(headerColor ?? "", activeColor ?? "");
        const separatorColor = getSeparatorColor(headerColor ?? "", activeColor ?? "");
        const workspacesPickerHoverColor = getWorkspacePickerHoverColor(headerColor ?? "");
        const css = [];
        css.push(`.${guid} { color: ${textColor}; background: ${headerColor}}`);
        css.push(`.${guid} .gd-header-menu-section { border-color: ${separatorColor}}`);
        css.push(`.${guid} .gd-header-menu-item:hover { border-color: ${itemHoverColor}}`);
        css.push(`.${guid} .gd-header-menu-item.active { border-color: var(--gd-palette-primary-base-from-theme, ${itemActiveColor})}`);
        css.push(`.${guid} .gd-header-project { border-color: ${separatorColor}}`);
        css.push(`.${guid} .gd-header-project:hover { background-color: ${workspacesPickerHoverColor}; color: ${textColor}}`);
        css.push(`.${guid} .hamburger-icon:not(.is-open) i { border-color: ${textColor}}`);
        css.push(`.${guid} .hamburger-icon:not(.is-open):after { border-color: ${textColor}}`);
        css.push(`.${guid} .hamburger-icon:not(.is-open):before { border-color: ${textColor}}`);
        stylesheetRef.current = addCssToStylesheet(`header-css-${guid}`, css.join("\n"), true);
    }, [state, activeColor, headerColor, headerTextColor]);
    useEffect(() => {
        createStyles();
    }, [createStyles]);
    const setOverlayMenu = useCallback((isOverlayMenuOpen) => {
        setState((prevState) => ({
            ...prevState,
            isOverlayMenuOpen,
            isHelpMenuOpen: false,
            isSearchMenuOpen: false,
            isNotificationsMenuOpen: false,
        }));
    }, []);
    const toggleSearchMenu = useCallback(() => {
        setState((prevState) => ({
            ...prevState,
            isSearchMenuOpen: !prevState.isSearchMenuOpen,
            isHelpMenuOpen: false,
            isNotificationsMenuOpen: false,
        }));
    }, []);
    const toggleNotificationsMenu = useCallback(() => {
        setState((prevState) => ({
            ...prevState,
            isNotificationsMenuOpen: !prevState.isNotificationsMenuOpen,
            isHelpMenuOpen: false,
            isSearchMenuOpen: false,
        }));
    }, []);
    const toggleAiChat = useCallback((e) => {
        onChatItemClick?.(e);
        setState((prevState) => ({
            ...prevState,
            isOverlayMenuOpen: false,
            isNotificationsMenuOpen: false,
            isHelpMenuOpen: false,
            isSearchMenuOpen: false,
        }));
    }, [onChatItemClick]);
    const closeNotificationsMenu = useCallback(() => {
        setState((prevState) => ({
            ...prevState,
            isNotificationsMenuOpen: false,
            isHelpMenuOpen: false,
            isSearchMenuOpen: false,
            isOverlayMenuOpen: false,
        }));
    }, []);
    const toggleHelpMenu = useCallback(() => {
        setState((prevState) => ({
            ...prevState,
            isHelpMenuOpen: !prevState.isHelpMenuOpen,
            isSearchMenuOpen: false,
            isNotificationsMenuOpen: false,
        }));
    }, []);
    const handleMenuItemClick = useCallback((item, event) => {
        if (state.isHelpMenuOpen) {
            setOverlayMenu(false);
        }
        onMenuItemClick?.(item, event);
    }, [state.isHelpMenuOpen, setOverlayMenu, onMenuItemClick]);
    const getHelpMenuLink = (icon = "gd-icon-header-help") => {
        const shouldOpenDropdown = state.responsiveMode && helpMenuItems.length > 0;
        return {
            key: HEADER_HELP_MENU_ITEM_ID,
            className: `s-menu-help ${icon}`,
            href: shouldOpenDropdown ? undefined : documentationUrl,
            onClick: shouldOpenDropdown ? toggleHelpMenu : undefined,
        };
    };
    const addHelpItemGroup = (itemGroups) => {
        return documentationUrl ? [...itemGroups, [getHelpMenuLink()]] : itemGroups;
    };
    const addAdditionalItems = (itemGroups) => {
        const additionalItems = [];
        if (search) {
            additionalItems.push({
                key: messages.search.id,
                className: "gd-icon-header-search",
                onClick: toggleSearchMenu,
            });
        }
        if (showChatItem) {
            const AiIcon = Icon["GenAI2"];
            additionalItems.push({
                key: messages.aiChatMobile.id,
                className: "gd-icon-header-ai",
                icon: _jsx(AiIcon, { width: 16, height: 16 }),
                onClick: toggleAiChat,
            });
        }
        if (notificationsPanel) {
            const AlertIcon = Icon["Alert"];
            additionalItems.push({
                key: messages.notifications.id,
                className: "gd-icon-header-notifications",
                icon: _jsx(AlertIcon, { width: 16, height: 16 }),
                onClick: toggleNotificationsMenu,
            });
        }
        if (!additionalItems.length) {
            return itemGroups;
        }
        return [...itemGroups, additionalItems];
    };
    const renderTrialCountdown = (expiredDate) => {
        // expiredDate is the last day that user can use the service
        const trialDaysLeft = differenceInCalendarDays(new Date(expiredDate), new Date()) + 1;
        if (trialDaysLeft === 1) {
            return _jsx(FormattedMessage, { id: "gs.header.countdown.lastDay" });
        }
        if (trialDaysLeft === 30) {
            return _jsx(FormattedMessage, { id: "gs.header.countdown.oneMonthLeft" });
        }
        if (trialDaysLeft > 1 && trialDaysLeft < 30) {
            return (_jsx(FormattedMessage, { id: "gs.header.countdown.numberOfDaysLeft", values: { number: trialDaysLeft } }));
        }
        if (trialDaysLeft > 30 && trialDaysLeft <= 91) {
            const currentDateWithoutTime = format(new Date(), "yyyy-MM-dd");
            const trialMonthsLeft = differenceInMonths(new Date(expiredDate), new Date(currentDateWithoutTime));
            return (_jsx(FormattedMessage, { id: "gs.header.countdown.numberOfMonthsLeft", values: { number: trialMonthsLeft + 1 } }));
        }
        return "";
    };
    const renderLogo = (logoLinkClassName) => {
        return (_jsx("a", { href: logoHref, onClick: onLogoClick, className: logoLinkClassName, children: _jsx("img", { src: logoUrl, title: logoTitle, onLoad: measureChildren, onError: measureChildren, alt: "" }) }));
    };
    const renderAccessibilityLogo = (logoLinkClassName, organizationName) => {
        const logoHrefAccesibilityText = intl.formatMessage({
            id: "gs.header.href.accessibility",
        });
        const imageAltAccessibilityText = intl.formatMessage({
            id: "gs.header.logo.title.accessibility",
        }, { organizationName: organizationName || "GoodData" });
        return (_jsx("a", { "aria-label": logoHrefAccesibilityText, title: logoHrefAccesibilityText, href: logoHref, onClick: onLogoClick, className: logoLinkClassName, children: _jsx("img", { src: logoUrl, title: logoTitle, onLoad: measureChildren, onError: measureChildren, alt: imageAltAccessibilityText }) }));
    };
    const renderSearchMenu = () => {
        return (_jsxs("div", { className: "gd-header-menu-search", children: [
                _jsx(Typography, { tagName: "h3", className: "gd-header-menu-search-title", children: _jsx(FormattedMessage, { id: "gs.header.search" }) }), _jsx(HeaderSearchProvider, { isOpen: state.isSearchMenuOpen, toggleOpen: toggleSearchMenu, children: search })
            ] }));
    };
    const renderNotificationsOverlay = () => {
        if (!notificationsPanel) {
            return null;
        }
        return (_jsxs("div", { className: "gd-header-menu-notifications", children: [
                _jsx(Typography, { tagName: "h3", className: "gd-header-menu-notifications-title", children: _jsx(FormattedMessage, { id: "gs.header.notifications" }) }), notificationsPanel({
                    isMobile: true,
                    closeNotificationsOverlay: closeNotificationsMenu,
                })] }));
    };
    const renderTrialItems = () => {
        if (expiredDate || showUpsellButton) {
            return (_jsxs("div", { className: "gd-header-menu-trial gd-header-measure", children: [expiredDate ? (_jsx("div", { className: "gd-header-expiration-date", children: renderTrialCountdown(expiredDate) })) : null, showUpsellButton ? (_jsx(HeaderUpsellButton, { onUpsellButtonClick: onUpsellButtonClick })) : null] }));
        }
        return null;
    };
    const renderLogoutButton = () => {
        const [logoutMenuItem] = accountMenuItems.filter((item) => item.key === LOGOUT_MENU_ITEM_ID);
        const LogoutIcon = Icon["Logout"];
        return logoutMenuItem ? (_jsxs("button", { className: "logout-button gd-button s-logout", onClick: (e) => {
                onMenuItemClick?.(logoutMenuItem, e);
            }, children: [
                _jsx(LogoutIcon, { className: "gd-icon-logout", color: theme?.palette?.complementary?.c0 }), _jsx("span", { className: "gd-button-text", children: _jsx(FormattedMessage, { id: "gs.header.logout" }) })
            ] })) : (false);
    };
    const renderVerticalMenu = () => {
        const menuItemsGroupsToRender = state.isHelpMenuOpen
            ? [[getHelpMenuLink("gd-icon-header-help-back"), ...helpMenuItems]]
            : showStaticHelpMenu
                ? [[getHelpMenuLink()]]
                : addHelpItemGroup(addAdditionalItems(menuItemsGroups));
        return (_jsxs("div", { className: "gd-header-menu-vertical-wrapper", children: [
                _jsx("div", { className: "gd-header-menu-vertical-header", children: _jsx(FormattedMessage, { id: "gs.header.menu" }) }), _jsxs("div", { className: "gd-header-menu-vertical-content", children: [
                        _jsx(HeaderMenu, { onMenuItemClick: handleMenuItemClick, sections: menuItemsGroupsToRender, className: "gd-header-menu-vertical" }), renderTrialItems()] }), _jsxs("div", { className: "gd-header-menu-vertical-footer", children: [!!badges && _jsx("div", { className: "gd-header-vertical-badges", children: badges }), _jsx("div", { className: "gd-header-menu-vertical-bottom-item", children: _jsx("span", { className: "gd-header-username gd-icon-user", children: userName }) }), _jsx("div", { children: renderLogoutButton() })
                    ] })
            ] }, "overlay-menu"));
    };
    const renderOverlayMenu = () => {
        let content = renderVerticalMenu();
        if (state.isSearchMenuOpen) {
            content = renderSearchMenu();
        }
        if (state.isNotificationsMenuOpen) {
            content = renderNotificationsOverlay() ?? null;
        }
        return (_jsx(Overlay, { alignPoints: [
                {
                    align: state.isSearchMenuOpen || state.isNotificationsMenuOpen ? "tl tl" : "tr tr",
                },
            ], closeOnOutsideClick: state.isOverlayMenuOpen, isModal: state.isOverlayMenuOpen, positionType: "fixed", onClose: () => {
                setOverlayMenu(false);
            }, children: content }, "header-overlay-menu"));
    };
    const renderMobileNav = () => {
        const iconClasses = cx({
            "hamburger-icon": true,
            "is-open": state.isOverlayMenuOpen,
            "search-open": state.isSearchMenuOpen,
            "notifications-open": state.isNotificationsMenuOpen,
        });
        return (_jsxs(_Fragment, { children: [
                _jsx("div", { "aria-label": intl.formatMessage({ id: "gs.header.mainMenu.ariaLabel" }), role: "button", tabIndex: 0, className: "hamburger-wrapper", onClick: () => {
                        setOverlayMenu(!state.isOverlayMenuOpen);
                    }, children: _jsx("div", { className: iconClasses, children: _jsx("i", {}) }, "hamburger-icon") }, "hamburger-wrapper"), state.isOverlayMenuOpen ? renderOverlayMenu() : null] }));
    };
    const renderStandardNav = () => {
        return (_jsxs("div", { className: "gd-header-stretch gd-header-menu-wrapper", children: [
                _jsx(HeaderMenu, { onMenuItemClick: onMenuItemClick, sections: menuItemsGroups, className: "gd-header-menu-horizontal" }), renderTrialItems(), showChatItem ? (_jsx(HeaderChatButton, { title: intl.formatMessage(messages.aiChat), onClick: onChatItemClick ?? (() => { }) })) : null, notificationsPanel
                    ? notificationsPanel({
                        isMobile: false,
                        closeNotificationsOverlay: closeNotificationsMenu,
                    })
                    : null, search ? (_jsx(HeaderSearchProvider, { isOpen: state.isSearchMenuOpen, toggleOpen: toggleSearchMenu, children: _jsx(HeaderSearchButton, { title: intl.formatMessage(messages.search), children: search }) })) : null, helpMenuItems.length ? (_jsx(HeaderHelp, { onMenuItemClick: onMenuItemClick, className: "gd-header-measure", helpMenuDropdownAlignPoints: helpDropdownAlign, items: helpMenuItems, disableDropdown: disableHelpDropdown, onHelpClicked: onHelpClick, helpRedirectUrl: helpRedirectUrl })) : null, _jsx(HeaderAccount, { userName: userName, onMenuItemClick: onMenuItemClick, className: "gd-header-measure", items: accountMenuItems }), badges ? _jsx("div", { className: "gd-header-badges gd-header-measure", children: badges }) : null] }));
    };
    const logoLinkClassName = cx({
        "gd-header-logo": true,
        "gd-header-measure": true,
        "gd-header-shrink": state.responsiveMode,
    });
    return (_jsxs("header", { ref: nodeRef, "aria-label": intl.formatMessage({ id: "gs.header.accessibility.label" }), className: cx("gd-header", state.guid, className), children: [isAccessibilityCompliant
                ? renderAccessibilityLogo(logoLinkClassName, organizationName ?? "")
                : renderLogo(logoLinkClassName), workspacePicker, state.responsiveMode ? renderMobileNav() : renderStandardNav()] }));
});
