import React, { useState, useEffect, createRef, useRef } from 'react';
import PropTypes from 'prop-types';
import { CSSTransition } from 'react-transition-group';
import { createNamespace } from '../../../../tools/namingTools';
import { useResponsive } from '../../../../tools/widths/useResponsive';
import { generateUniqueID } from '../../../../tools/helpers';
import { generateUserLinks } from '../../../../tools/components/header';
import { getLogoAlt } from '../../../../tools/themeSettings';
import { cartPreviewStore } from '../../../../store/cartPreview';
import { LEFT, RIGHT } from '../../../../constants/alignment';
import { CART_URL } from '../../../../constants/actions';
import withListener from '../../../withListener';
import HeaderLogo from '../../../../atoms/logo/Logo';

import { headerHomeBarSchemaForm, headerHomeBarDefaultSettings, headerHomeBarDefaultData } from '../../../../constants/components/schemas/header';
import { headerHomeBarSettingsShape, headerHomeBarDataShape } from '../../../../constants/components/prop-types/header';
import { LOGO_TARGET_CUSTOM_URL, CART_OVERLAY_TRANSITION_DURATION, SEARCH_BAR_IN_HOME_BAR, NO_SEARCH_BAR } from '../../../../constants/components/header';
import { NO_LOGO } from '../../../../constants/logo';

import Link from '../../../../atoms/link/Link';
import Badge from '../../../../atoms/badge/Badge';
import Button from '../../../../atoms/button/Button';
import Icon from '../../../../atoms/icon/Icon';
import ButtonIcon from '../../../../atoms/button-icon/ButtonIcon';
import Avatar from '../../../../atoms/avatar/Avatar';
import HeaderMobile from '../common/header-mobile/HeaderMobile';
import HeaderSearchBar from '../common/header-search-bar/HeaderSearchBar';
import HeaderCartOverlay from '../common/header-cart-overlay/HeaderCartOverlay';
import { MENUS } from '../../../../constants/menus';
import { LOGIN_LINK, SIGN_UP_LINK } from '../../../../constants/links';
import './styles/HeaderHomeBar.scss';
import HeaderNavigation from '../common/header-navigation/HeaderNavigation';

const n = createNamespace('HeaderHomeBar');

const getLinkIcon = (iconObject, alternative) => {
    if (iconObject && iconObject.url) {
        return { iconSrc: iconObject.url };
    }
    return { icon: alternative };
};

let cartTimer;

const HeaderHomeBar = ({
    data: {
        logo,
        user,
        marketplaceName,
        searchBar,
        i18n,
        categories,
        listingEndpoint,
        baseUrl,
        toggleHeaderScrimFunction,
        locale,
        nav,
        config
    },
    settings,
    menus
}) => {
    const settingsWithDefaults = {
        ...HeaderHomeBar.defaultProps.settings,
        ...settings
    };
    const {
        displayCart: displayCartKnob,
        displayLoginLink: displayLoginLinkKnob,
        displayRegistrationLink: displayRegistrationLinkKnob,
        customCartIcon,
        customSignInIcon,
        logoTheme,
        logoTargetType,
        logoTargetCustomUrl,
        logoHeight,
        homeBarTextSize,
        homeBarPadding,
        homeBarBackgroundColor,
        homeBarBorderColor,
        homeBarTextColor,
        homeBarTextHoverColor,
        homeBarTextActiveColor,
        searchBackgroundColor,
        searchIconColor,
        searchButtonColor,
        searchBorderColor,
        searchBarMaxWidth,
        searchBorderVisible,
        searchCornerRadius,
        searchIcon,
        searchPlaceholder: settingSearchPlaceholder,
        searchBarHeight,
        searchBarLocation,
        homeBarTextAlignment
    } = settingsWithDefaults;
    const [isCartVisible, setCartVisibilityState] = useState(false);
    const [hasNewProductAdded, setHasNewProductAdded] = useState(false);
    const [userDropdownOpen, setUserDropdownOpen] = useState(false);
    const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
    const [alreadyInCart, setAlreadyInCart] = useState(false);
    const [addToCartError, setAddToCartError] = useState(false);

    const { cart, fetchCart, clearCart, isLoading: isCartLoading } = cartPreviewStore();
    const localeCode = locale?.code;

    const cartOverlayRef = useRef();
    const { mediumDown: isMobile } = useResponsive();

    const updateCartContentRef = ref => {
        cartOverlayRef.current = ref;
    };

    const closeCartOverlay = event => {
        const { target } = event;
        const cartOverlay = cartOverlayRef.current;
        if (!cartOverlay) {
            return;
        }
        if (!cartOverlay.contains(target)) {
            setCartVisibilityState(false);
            toggleHeaderScrimFunction(false);
        }
    };

    const setCartAutoCloseTimer = () => {
        cartTimer = setTimeout(() => {
            // eslint-disable-next-line no-use-before-define
            closeCart();
        }, 400);
    };

    const resetCartAutoCloseTimer = () => {
        clearTimeout(cartTimer);
    };

    const openCartOverlay = () => {
        resetCartAutoCloseTimer();
        setCartVisibilityState(true);
        toggleHeaderScrimFunction(true);
    };

    const closeCart = () => {
        setCartVisibilityState(false);
        toggleHeaderScrimFunction(false);
    };

    const toggleMobileMenu = () => {
        setMobileMenuOpen(!mobileMenuOpen);
        toggleHeaderScrimFunction(!mobileMenuOpen);
    };

    useEffect(() => {
        const addToCartFunc = async () => {
            // re-fetch
            clearCart();
            await fetchCart(localeCode);

            setHasNewProductAdded(true);
            openCartOverlay();
        };

        const alreadyInCartFunc = () => {
            setHasNewProductAdded(false);
            setAlreadyInCart(true);
            openCartOverlay();
        };

        const addToCartErrorFunc = () => {
            setHasNewProductAdded(false);
            setAddToCartError(true);
            openCartOverlay();
        };

        document.addEventListener('universalnav:add:cart', addToCartFunc);
        document.addEventListener('universalnav:alreadyInCart:cart', alreadyInCartFunc);
        document.addEventListener('universalnav:error:cart', addToCartErrorFunc);

        document.addEventListener('click', closeCartOverlay);
        return () => {
            document.removeEventListener('universalnav:add:cart', addToCartFunc);
            document.removeEventListener('universalnav:alreadyInCart:cart', alreadyInCartFunc);
            document.removeEventListener('universalnav:error:cart', addToCartErrorFunc);
            document.removeEventListener('click', closeCartOverlay);
        };
    }, []);

    // Close user dropdown if click outside of it
    const userDropdownRef = createRef();
    useEffect(() => {
        const closeDropdownOnClickOutside = event => {
            const { target } = event;
            const userDropdownMenuElem = userDropdownRef.current;
            if (!userDropdownMenuElem) {
                return;
            }
            if (!userDropdownMenuElem.contains(target)) {
                setUserDropdownOpen(false);
            }
        };
        document.addEventListener('click', closeDropdownOnClickOutside);
        return () => document.removeEventListener('click', closeDropdownOnClickOutside);
    }, [
        userDropdownOpen,
        setUserDropdownOpen,
        userDropdownRef
    ]);

    // fetch once, cart is updated by zustand store
    useEffect(() => {
        fetchCart(localeCode);
    }, [fetchCart, localeCode]);

    const i18nWithDefaults = { ...HeaderHomeBar.defaultProps.data.i18n, ...i18n };
    const displaySearchBar = isMobile
        ? searchBarLocation !== NO_SEARCH_BAR.value
        : searchBarLocation === SEARCH_BAR_IN_HOME_BAR.value;

    const {
        label: searchBarLabel,
        placeholder: searchBarPlaceholder
    } = searchBar;
    const { isLoggedIn: isUserLoggedIn, name: userName, given_name: givenName, picture } = user;

    const componentVariables = {
        'bar-vertical-padding': `${homeBarPadding ?? headerHomeBarDefaultSettings.homeBarPadding}px`,
        'background-color': homeBarBackgroundColor,
        'border-color': homeBarBorderColor,
        'logo-height': `${logoHeight ?? headerHomeBarDefaultSettings.logoHeight}px`,
        'text-color': homeBarTextColor,
        'text-hover-color': homeBarTextHoverColor,
        'text-active-color': homeBarTextActiveColor,
        'header-nav-bar-padding': `${homeBarPadding ?? headerHomeBarDefaultSettings.homeBarPadding}px`,
        'cart-overlay-transition-durantion': CART_OVERLAY_TRANSITION_DURATION && `${CART_OVERLAY_TRANSITION_DURATION}ms`
    };
    const displayCart = displayCartKnob && isUserLoggedIn;
    const displayRegistrationLink = displayRegistrationLinkKnob && !isUserLoggedIn;
    const displayLogo = (logoTheme !== NO_LOGO);
    const displayLoginLink = displayLoginLinkKnob && !isUserLoggedIn;
    const displayUserDropdown = isUserLoggedIn && !isMobile; // If mobile, will be in the burger menu
    const logoTargetHref = (logoTargetType === LOGO_TARGET_CUSTOM_URL.value)
        ? logoTargetCustomUrl
        : '/';
    const iconPosition = isMobile ? RIGHT.value : LEFT.value;
    const onlyQuickNav = !displaySearchBar && !displayLogo && !isMobile;

    const homeBarNavItems = menus && menus[MENUS.HOME_BAR_MENU] && menus[MENUS.HOME_BAR_MENU].menu;
    const burgerButtonIcon = mobileMenuOpen ? 'close' : 'burger';

    const toggleUserDropdownOpen = () => setUserDropdownOpen(!userDropdownOpen);
    const searchBarProps = {
        ...n('searchBar').props,
        searchBackgroundColor,
        searchBorderColor,
        searchCornerRadius,
        searchBorderVisible,
        searchIconColor,
        searchButtonColor,
        searchIcon,
        label: searchBarLabel,
        searchPlaceholder: settingSearchPlaceholder || searchBarPlaceholder,
        searchBarMaxWidth,
        searchBarHeight
    };

    const channelSettings = config && config?.channelSettings;
    const userDropdownLinks = generateUserLinks(baseUrl, user, i18nWithDefaults, channelSettings);
    const wrapperModifiers = [
        `${homeBarTextSize}-text`,
        onlyQuickNav && 'only-quicknav'
    ];

    return (
        <div {...n('homeBar').withTestId().props}>
            <div {...n('wrapper', wrapperModifiers).withVariables(componentVariables).withTestId().props}>
                {isMobile && (
                    <Button
                        {...n('burgerBtn').withTestId().props}
                        buttonType="icon"
                        onClick={toggleMobileMenu}
                    >
                        <Icon
                            {...n('burgerIcon').props}
                            width="15px"
                            type={burgerButtonIcon}
                            fill={null}
                        />
                    </Button>
                )}
                {(isMobile && mobileMenuOpen) && (
                    <HeaderMobile
                        {...n('mobileMenu').props}
                        categories={categories}
                        user={user}
                        settings={settings}
                        i18n={i18nWithDefaults}
                        baseUrl={baseUrl}
                        listingEndpoint={listingEndpoint}
                        nav={nav}
                        locale={config?.locale}
                        picture={picture}
                        channelSettings={config?.channelSettings}
                    />
                )}
                {displayLogo && (
                    <div {...n('logoWrapper').withTestId().props}>
                        <HeaderLogo
                            defaultLogo={logo}
                            selectedLogo={logoTheme}
                            url={logoTargetHref}
                            width={logoHeight}
                            alt={getLogoAlt(logoTheme) || marketplaceName || ''}
                        />
                    </div>
                )}
                {!isMobile && (
                    <HeaderNavigation
                        {...n('navigation').props}
                        i18n={i18nWithDefaults}
                        items={homeBarNavItems}
                        align={homeBarTextAlignment}
                        locale={config?.locale}
                        textSize={homeBarTextSize}
                        listingEndpoint={config && config.listingEndpoint}
                        menuType={MENUS.HOME_BAR_MENU}
                        toggleHeaderScrimFunction={toggleHeaderScrimFunction}
                        navAriaLabel={i18nWithDefaults?.header?.homeBarLabel}
                    />
                )}
                {displaySearchBar && (
                    <div {...n('centerSearch').withVariables({ 'center-search-width': `${searchBarMaxWidth}px` }).props}>
                        <HeaderSearchBar settings={searchBarProps} data={{ ...config }} />
                    </div>
                )}
                {(displayUserDropdown || displayLoginLink || displayRegistrationLink || displayCart) && (
                    <nav {...n('homeBarNav', 'quick-links').props} aria-label={i18nWithDefaults?.header?.quickLinksLabel}>
                        <ul {...n('homeBarNavList').props}>
                            {displayLoginLink && (
                                <li {...n('homeBarNavItem').withTestId('login').props}>
                                    <Link
                                        {...n('homeBarNavLink').props}
                                        {...getLinkIcon(customSignInIcon, 'user')}
                                        href={LOGIN_LINK}
                                        iconPosition={iconPosition}
                                        iconClass={n('homeBarNavIcon').props.className}
                                    >
                                        {i18nWithDefaults['sign.in']}
                                    </Link>
                                </li>
                            )}
                            {displayUserDropdown && (
                                <li {...n('homeBarNavItem', 'user-dropdown').props}>
                                    <ButtonIcon
                                        {...n('userDropdownBtn').withTestId('userDropdown').props}
                                        type="link"
                                        icon={!userDropdownOpen ? 'angleDown' : 'angleUp'}
                                        iconPosition="right"
                                        onClick={toggleUserDropdownOpen}
                                    >
                                        <span {...n('userLabel').props}>
                                            <Avatar
                                                {...n('userAvatar').props}
                                                name={userName}
                                                size={25}
                                                borderRadius={3}
                                                picture={picture}
                                            />
                                            <span {...n('userName').props}>{givenName}</span>
                                        </span>
                                    </ButtonIcon>
                                    {Boolean(userDropdownLinks && userDropdownLinks.length) && (
                                        <ul {...n('userDropdownList', userDropdownOpen && 'visible').withTestId().props} ref={userDropdownRef}>
                                            {userDropdownLinks.map(({ label, url }) => (
                                                <li {...n('userDropdownItem').props} key={generateUniqueID([label, url])}>
                                                    <Link {...n('userDropdownLink').props} href={url}>{label}</Link>
                                                </li>
                                            ))}
                                        </ul>
                                    )}
                                </li>
                            )}
                            {displayRegistrationLink && (
                                <li {...n('homeBarNavItem').withTestId('registration').props}>
                                    <Link
                                        {...n('homeBarNavLink').props}
                                        href={SIGN_UP_LINK}
                                        {...getLinkIcon(customSignInIcon, 'user')}
                                        iconPosition={iconPosition}
                                        iconClass={n('homeBarNavIcon').props.className}
                                    >
                                        {i18nWithDefaults['sign.up']}
                                    </Link>
                                </li>
                            )}
                            {displayCart && (
                                <li
                                    {...n('homeBarNavItem', 'cart').withTestId('cart').props}
                                >
                                    <div {...n('homeBarNavLink', 'cart').props}>
                                        <Link
                                            href={CART_URL}
                                            {...getLinkIcon(customCartIcon, 'cart')}
                                            onMouseOver={!isMobile ? openCartOverlay : undefined}
                                            onMouseLeave={setCartAutoCloseTimer}
                                            onFocus={!isMobile ? openCartOverlay : undefined}
                                            iconPosition={iconPosition}
                                            iconClass={n('cartIcon').props.className}
                                            hiddenText={isMobile}
                                            iconExtraContent={cart && cart.itemsCount ? (
                                                <Badge
                                                    {...n('cartNotification').props}
                                                    label={cart.itemsCount.toString()}
                                                />
                                            ) : null}
                                        >
                                            {i18nWithDefaults.cart.cart}
                                        </Link>
                                    </div>
                                    <CSSTransition
                                        in={isCartVisible}
                                        timeout={CART_OVERLAY_TRANSITION_DURATION}
                                        unmountOnExit
                                    >
                                        <HeaderCartOverlay
                                            {...n('cartOverlay').props}
                                            onClose={closeCart}
                                            onMouseOver={resetCartAutoCloseTimer}
                                            onMouseFocus={resetCartAutoCloseTimer}
                                            onMouseLeave={setCartAutoCloseTimer}
                                            cart={cart}
                                            isLoading={isCartLoading}
                                            isLoggedIn={isUserLoggedIn}
                                            i18n={i18nWithDefaults}
                                            cartRefCallback={updateCartContentRef}
                                            alreadyInCartNotif={alreadyInCart}
                                            addToCartError={addToCartError}
                                            hasNewProductAdded={hasNewProductAdded}
                                        />
                                    </CSSTransition>
                                </li>
                            )}
                        </ul>
                    </nav>
                )}
            </div>
        </div>
    );
};

HeaderHomeBar.schema = () => ({
    name: 'Header Home Bar',
    title: 'uieditor.sfbComponent.header.homeBar.title',
    iconName: 'universalNavHome',
    form: headerHomeBarSchemaForm
});

HeaderHomeBar.propTypes = {
    ...headerHomeBarDataShape,
    ...{
        settings: PropTypes.shape(headerHomeBarSettingsShape)
    }
};

HeaderHomeBar.defaultProps = {
    data: headerHomeBarDefaultData,
    settings: headerHomeBarDefaultSettings
};

export default withListener(HeaderHomeBar);
