import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import withListener from '../withListener';
import { createNamespace } from '../../tools/namingTools';
import { useResponsive } from '../../tools/widths/useResponsive';
import { headerDataShape } from '../../constants/components/prop-types/header';
import { orderableComponentsShape } from '../../constants/components/prop-types/orderable-component';
import { menusPropTypes } from '../../constants/components/prop-types/menu';
import HeaderScrim from './atoms/common/header-scrim/HeaderScrim';
import ChildrenOrderableContainer from '../childrenOrderableContainer/ChildrenOrderableContainer';
import './styles/Header.scss';
import usePreviousValue from '../../tools/hooks/usePreviousValue';
import HeaderHomeBar from './atoms/header-home-bar/HeaderHomeBar';
import HeaderNavigationBar from './atoms/header-navigation-bar/HeaderNavigationBar';
import HeaderAuxiliaryBar from './atoms/header-auxiliary-bar/HeaderAuxiliaryBar';
import { getComponentSchemaName } from '../../tools/componentSchemaTools';
import { isNameMatch } from '../../tools/stringTools';
import { getNestedShareableComponentKeys, getNestedShareableComponents } from '../../tools/nestedShareableComponentsTools';
import PreviewBanner from './atoms/preview-banner/PreviewBanner';
import { MENUS } from '../../constants/menus';

const n = createNamespace('Header');

export const HeaderComponent = ({
    data: {
        common,
        config,
        i18n,
        meta,
        nav
    },
    settings,
    menus
}) => {
    const { components, orderableComponents } = settings;
    const shareableComponentKeys = getNestedShareableComponentKeys(components);
    const [scrimOpen, setScrimOpen] = useState(false);
    const prevOrderableComponents = usePreviousValue(orderableComponents);
    const [headerOrderableComponents, setHeaderOrderableComponents] = useState([]);
    const { searchBar } = common;
    const { logo, user, marketplaceName, locale, pageId } = config;
    const { categories } = nav.primary;

    const homeBarProps = {
        logo,
        user,
        marketplaceName,
        searchBar,
        i18n,
        categories,
        listingEndpoint: config.listingEndpoint,
        baseUrl: meta.baseUrl,
        toggleHeaderScrimFunction: setScrimOpen,
        locale,
        nav,
        config
    };

    const navigationBarProps = {
        searchBar,
        categories,
        config,
        nav,
        i18n,
        toggleHeaderScrimFunction: setScrimOpen
    };

    const auxiliaryBarProps = {
        searchBar,
        categories,
        config,
        locale,
        i18n,
        pageId
    };

    const getData = name => {
        if (isNameMatch(name, getComponentSchemaName(HeaderHomeBar))) {
            return homeBarProps;
        }
        if (isNameMatch(name, getComponentSchemaName(HeaderNavigationBar))) {
            return navigationBarProps;
        }
        if (isNameMatch(name, getComponentSchemaName(HeaderAuxiliaryBar))) {
            return auxiliaryBarProps;
        }
        return {};
    };

    const getBarMenus = barMenuConstant => ((menus && menus[barMenuConstant])
        ? { [barMenuConstant]: menus[barMenuConstant] } : {});

    const { mediumDown: isMobile } = useResponsive();

    const getBarMenuItemsForMobile = () => {
        if (isMobile) {
            return {
                auxBarMenuItems: getBarMenus(MENUS.AUXILIARY_BAR_MENU),
                navBarMenuItems: getBarMenus(MENUS.NAVIGATION_BAR_MENU),
                homeBarMenuItems: getBarMenus(MENUS.HOME_BAR_MENU)
            };
        }
        return {};
    };

    const getSettings = id => ({
        ...components[id],
        ...Object.assign({}, ...getNestedShareableComponents(shareableComponentKeys, components)),
        ...getBarMenuItemsForMobile()
    });

    const getMenus = name => {
        if (isNameMatch(name, getComponentSchemaName(HeaderHomeBar))) {
            return getBarMenus(MENUS.HOME_BAR_MENU);
        }
        if (isNameMatch(name, getComponentSchemaName(HeaderAuxiliaryBar))) {
            return getBarMenus(MENUS.AUXILIARY_BAR_MENU);
        }
        if (isNameMatch(name, getComponentSchemaName(HeaderNavigationBar))) {
            return getBarMenus(MENUS.NAVIGATION_BAR_MENU);
        }
        return {};
    };

    useEffect(() => {
        if (prevOrderableComponents !== orderableComponents) {
            const data = [];
            orderableComponents.forEach(({ id, name, isVisible }) => {
                if (isVisible) {
                    data.push({
                        id,
                        name,
                        data: getData(name),
                        settings: getSettings(id),
                        menus: getMenus(name)
                    });
                }
            });
            setHeaderOrderableComponents(data);
        }
    }, [orderableComponents]);

    return (
        <>
            <PreviewBanner />
            <div {...n('wrapper').withTestId().props}>
                <HeaderScrim
                    {...n('scrim').props}
                    visible={scrimOpen}
                />
                <ChildrenOrderableContainer
                    childrenOrderableComponents={headerOrderableComponents}
                />
            </div>
        </>
    );
};

HeaderComponent.schema = () => ({
    name: 'Header',
    title: 'uieditor.sfbComponent.header.title',
    iconName: 'header',
    hasChildrenComponents: true,
    menus: [MENUS.HOME_BAR_MENU, MENUS.AUXILIARY_BAR_MENU, MENUS.NAVIGATION_BAR_MENU],
    marketplaceData: {
        common: 'common',
        config: 'config',
        cart: 'cart',
        i18n: 'i18n',
        meta: 'meta',
        nav: 'nav'
    }
});

HeaderComponent.propTypes = {
    data: PropTypes.shape(headerDataShape),
    settings: PropTypes.shape({
        components: PropTypes.object,
        orderableComponents: PropTypes.arrayOf(orderableComponentsShape)
    }),
    menus: menusPropTypes
};

HeaderComponent.defaultProps = {
    data: {},
    settings: {
        components: {},
        orderableComponents: []
    },
    menus: {}
};

export default withListener(HeaderComponent);
