import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { createNamespace } from '../../../../../tools/namingTools';
import { useResponsive } from '../../../../../tools/widths/useResponsive';
import { useContainerWidth } from '../../../../../tools/widths/useContainerWidth';
import { getNumberOfItemsThatFit } from '../../../../../tools/components/headerNavigation';
import { NAVIGATION_TEXT_ALIGN, NAVIGATION_TEXT_SIZE } from '../../../../../constants/components/header';
import { categoryShape, headerCategoriesMenuSettingsShape } from '../../../../../constants/components/prop-types/header';
import { headerCategoriesMenuDefaultSettings } from '../../../../../constants/components/schemas/header';
import { getPropValue } from '../../../../../tools/objectTools';
import { getListingUrlForProductLines } from '../../../../../tools/urlTools';
import ButtonIcon from '../../../../../atoms/button-icon/ButtonIcon';
import Link from '../../../../../atoms/link/Link';
import SubMenu from './subMenu/SubMenu';
import { MENUS } from '../../../../../constants/menus';

import HeaderCategoriesMenu from '../header-categories-menu/HeaderCategoriesMenu';

import './styles/HeaderNavigation.scss';
import { TARGET_BLANK } from '../../../../../constants/buttons';

const n = createNamespace('HeaderNavigation');

const CATEGORIES_OPEN_FLAG = 'categories_open';

const HeaderNavigation = ({
    items: navItems,
    align: navAlignment,
    i18n: i18nProp,
    textSize,
    categories,
    categoriesMenuSettings,
    listingEndpoint,
    menuType,
    locale,
    toggleHeaderScrimFunction,
    navAriaLabel,
    ...otherProps
}) => {
    const [openSubmenus, setOpenSubmenus] = useState([]);
    const [containerRef, containerWidth] = useContainerWidth();
    const { mediumDown: isMobile } = useResponsive();

    let timer;

    const navigationRef = useRef(null);
    const menuItemsRefs = useRef([]);
    const moreMenuItemsRefs = useRef([]);
    const moreButtonRef = useRef();

    const isHomeBarMenu = menuType && menuType === MENUS.HOME_BAR_MENU;
    const isNavBarMenu = menuType && menuType === MENUS.NAVIGATION_BAR_MENU;
    const setMenuItemRef = (refsArray, node) => {
        if (node && !refsArray.includes(node)) {
            refsArray.push(node);
        }
    };

    const resetMenuItemsVisibility = () => {
        moreButtonRef.current.style.removeProperty('display');
        menuItemsRefs.current.forEach(elem => elem.style.removeProperty('display'));
        moreMenuItemsRefs.current.forEach(elem => elem.style.removeProperty('display'));
    };

    const updateMenuItemsVisibility = numberOfVisibleElements => {
        if (numberOfVisibleElements === menuItemsRefs.current.length) {
            moreButtonRef.current.style.setProperty('display', 'none');
            return;
        }
        menuItemsRefs.current.forEach((element, index) => {
            if (index >= numberOfVisibleElements) {
                element.style.setProperty('display', 'none');
            }
        });
        const nbrItemsInMoreToDisplay = (categories && categories.length)
            ? numberOfVisibleElements - 1
            : numberOfVisibleElements;
        moreMenuItemsRefs.current.forEach((element, index) => {
            if (index < nbrItemsInMoreToDisplay) {
                element.style.setProperty('display', 'none');
            }
        });
    };

    const updateNumberOfVisibleItems = () => {
        if (menuItemsRefs.current.length === 0 || moreMenuItemsRefs.current.length === 0 || containerWidth === 0) {
            return;
        }

        resetMenuItemsVisibility();

        // Find number of items that fit
        const numberOfItemsThatFit = getNumberOfItemsThatFit(menuItemsRefs, moreButtonRef, containerWidth);
        updateMenuItemsVisibility(numberOfItemsThatFit);
    };

    useEffect(updateNumberOfVisibleItems);

    if ((!navItems || !navItems.length) && (!categories || !categories.length)) {
        return null;
    }

    const getNumberOfVisibleMenuItems = navItems.filter(({ isVisible }) => isVisible === true).length;

    const i18n = { ...HeaderNavigation.defaultProps.i18n, ...i18nProp };

    const {
        className: extraClass,
        'data-testid': parentTestId,
        withMoreButton
    } = otherProps;

    const closeCategories = () => {
        const newState = [...openSubmenus];
        newState.pop();
        setOpenSubmenus(newState);
        toggleHeaderScrimFunction(false);
    };

    const setCloseTimer = () => {
        timer = setTimeout(() => {
            closeCategories();
        }, 350);
    };

    const resetAutoCloseTimer = () => {
        clearTimeout(timer);
    };

    const caretIcon = isMobile ? 'caretRight' : 'angleDown';
    const renderNavItem = item => {
        const { isVisible, openInNewTab, children, uuid, editorType, customData } = item;
        const titleText = getPropValue(item, 'title.value');
        let linkUrl = getPropValue(item, 'link.value');

        if (!isVisible || !titleText) {
            return null;
        }

        if (editorType === 'PRODUCT_LINES') {
            linkUrl = getListingUrlForProductLines(locale.code, customData && customData.externalUUID);
        }
        const hasChildren = children && children.length > 0;
        const target = openInNewTab ? TARGET_BLANK : null;

        const openSubmenu = () => {
            toggleHeaderScrimFunction(false);
            resetAutoCloseTimer();
            setOpenSubmenus([item]);
        };

        const submenuIsOpen = openSubmenus.includes(item);
        const itemModifiers = [];

        return (
            <li
                {...n('item', itemModifiers).withTestId('menuItem').props}
                ref={r => setMenuItemRef(menuItemsRefs.current, r)}
                key={uuid}
            >
                {hasChildren ? (
                    <>
                        <ButtonIcon
                            {...n('btnMenu').props}
                            icon={caretIcon}
                            iconPosition="right"
                            iconClass={n('btnMenuIcon').props.className}
                            textClass={n('btnMenuText').props.className}
                            onFocus={openSubmenu}
                            onBlur={setCloseTimer}
                            onMouseOver={openSubmenu}
                            onMouseLeave={setCloseTimer}
                            url={linkUrl || ''}
                            openUrlInNewTab={openInNewTab}
                        >
                            {titleText}
                        </ButtonIcon>
                        <SubMenu
                            subMenuItems={children}
                            modifiers={submenuIsOpen ? ['visible'] : []}
                            locale={locale}
                            onFocus={resetAutoCloseTimer}
                            onBlur={setCloseTimer}
                            onMouseOver={resetAutoCloseTimer}
                            onMouseLeave={setCloseTimer}

                        />
                    </>
                ) : (
                    <Link
                        {...n('link').props}
                        href={linkUrl || ''}
                        target={target}
                    >
                        {titleText}
                    </Link>
                )}
            </li>
        );
    };

    const openCategories = () => {
        resetAutoCloseTimer();
        toggleHeaderScrimFunction(true);
        setOpenSubmenus([CATEGORIES_OPEN_FLAG]);
    };

    const categoriesMenuProps = {
        ...n('subMenu', [
            'categories',
            openSubmenus.includes(CATEGORIES_OPEN_FLAG) && 'visible'
        ]).props,
        categories,
        i18n,
        listingEndpoint,
        settings: categoriesMenuSettings,
        onFocus: resetAutoCloseTimer,
        onBlur: setCloseTimer,
        onMouseOver: resetAutoCloseTimer,
        onMouseLeave: setCloseTimer
    };

    return (
        <>
            <div {...n('widthReference', [isHomeBarMenu && 'hidden']).withTestId('widthReference').props} ref={containerRef} />
            <div {...n('wrapper', [textSize]).withTestId(parentTestId).withClass(extraClass).props}>
                <nav
                    {...n('nav').props}
                    aria-label={navAriaLabel || i18n.mainNavigation}
                    ref={navigationRef}
                >
                    <ul {...n('list', [navAlignment && `align-${navAlignment}`]).withTestId('navList').props}>
                        {isNavBarMenu && (
                            <li
                                ref={r => setMenuItemRef(menuItemsRefs.current, r)}
                                {...n('item').withTestId('menuItem').props}
                            >
                                <ButtonIcon
                                    {...n('btnMenu').props}
                                    icon={caretIcon}
                                    iconPosition="right"
                                    iconClass={n('btnMenuIcon').props.className}
                                    textClass={n('btnMenuText').props.className}
                                    onFocus={openCategories}
                                    onBlur={setCloseTimer}
                                    onMouseOver={openCategories}
                                    onMouseLeave={setCloseTimer}
                                >
                                    {i18n.allProducts}
                                </ButtonIcon>
                                <HeaderCategoriesMenu {...categoriesMenuProps} />
                            </li>
                        )}
                        {navItems.map(renderNavItem)}
                        {withMoreButton && !!getNumberOfVisibleMenuItems && (
                            <li
                                ref={moreButtonRef}
                                {...n('item').withTestId('menuItem').props}
                            >
                                <ButtonIcon
                                    {...n('btnMenu').props}
                                    icon={caretIcon}
                                    iconPosition="right"
                                    iconClass={n('btnMenuIcon').props.className}
                                    textClass={n('btnMenuText').props.className}
                                >
                                    {i18n.header.more}
                                </ButtonIcon>
                                <SubMenu
                                    subMenuItems={navItems}
                                    setItemsArrayFunction={r => setMenuItemRef(moreMenuItemsRefs.current, r)}
                                    locale={locale}
                                    onFocus={resetAutoCloseTimer}
                                    onBlur={setCloseTimer}
                                    onMouseOver={resetAutoCloseTimer}
                                    onMouseLeave={setCloseTimer}
                                />
                            </li>
                        )}
                    </ul>
                </nav>
            </div>
        </>
    );
};

HeaderNavigation.propTypes = {
    items: PropTypes.arrayOf(PropTypes.shape()),
    align: PropTypes.oneOf(NAVIGATION_TEXT_ALIGN.map(({ value }) => value)),
    i18n: PropTypes.shape({
        mainNavigation: PropTypes.string,
        header: PropTypes.shape({
            more: PropTypes.string
        }),
        allProducts: PropTypes.string
    }),
    listingEndpoint: PropTypes.string,
    textSize: PropTypes.oneOf(NAVIGATION_TEXT_SIZE.map(({ value }) => value)),
    ariaLabel: PropTypes.string,
    categories: PropTypes.arrayOf(PropTypes.shape(categoryShape)),
    categoriesMenuSettings: PropTypes.shape(headerCategoriesMenuSettingsShape),
    menuType: PropTypes.string,
    locale: PropTypes.object,
    toggleHeaderScrimFunction: PropTypes.func,
    navAriaLabel: PropTypes.string
};

HeaderNavigation.defaultProps = {
    items: [],
    align: null,
    listingEndpoint: '/',
    i18n: {
        mainNavigation: 'Header Navigation Bar',
        header: {
            more: 'More ...'
        },
        allProducts: 'All Products'
    },
    textSize: undefined,
    ariaLabel: null,
    categories: [],
    categoriesMenuSettings: headerCategoriesMenuDefaultSettings,
    menuType: '',
    locale: {
        code: 'en-US'
    },
    toggleHeaderScrimFunction: () => {},
    navAriaLabel: ''
};

export default HeaderNavigation;
