import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { createNamespace } from '../../../../../tools/namingTools';

import { THEME_PRIMARY, THEME_SECONDARY } from '../../../../../constants/buttons';
import { CART_URL } from '../../../../../constants/actions';
import { cartShape } from '../../../../../constants/components/prop-types/header';
import { generateUniqueID } from '../../../../../tools/helpers';
import { useDebounceResize } from '../../../../../tools/dimensions/useDebounceResize';

import Icon from '../../../../../atoms/icon/Icon';
import Preloader from '../../../../../atoms/preloader/Preloader';
import ButtonIcon from '../../../../../atoms/button-icon/ButtonIcon';
import CartEditionPreview from '../../../../../atoms/cart-edition-preview/CartEditionPreview';
import CartAddonPreview from '../../../../../atoms/cart-addon-preview/CartAddonPreview';

import './styles/HeaderCartOverlay.scss';

const n = createNamespace('HeaderCartOverlay');

const titleId = 'cartOverlayTitle';
const contentId = 'cartOverlayContent';

const renderAddon = ({ itemDetails: addonDetails = {} }) => {
    const { id, branding: { name } } = addonDetails;

    return (
        <div {...n('addon').props} key={generateUniqueID([id, name])}>
            <CartAddonPreview {...addonDetails} variant="cart-overlay" />
        </div>
    );
};

const HeaderCartOverlay = ({
    cart,
    isLoggedIn,
    isLoading,
    hasNewProductAdded,
    onClose,
    onMouseLeave,
    onMouseOver,
    onFocus,
    className,
    addToCartError,
    alreadyInCartNotif,
    cartRefCallback,
    i18n
}) => {
    const [isScrollEnabled, setScrollState] = useState(false);
    const [cartMaxHeight, setCartMaxHeight] = useState(0);
    const cartContentRef = useRef();

    const setCartRef = cartRef => {
        cartContentRef.current = cartRef;
        if (cartRefCallback) {
            cartRefCallback(cartRef);
        }
    };

    const setCartHeight = () => {
        if (!cartContentRef.current) {
            return;
        }
        const cartContentNode = cartContentRef.current;
        const cartBounds = cartContentNode.getBoundingClientRect();
        setCartMaxHeight(document.documentElement.clientHeight - cartBounds.top);
        setScrollState(cartBounds.height >= cartMaxHeight);
    };
    useDebounceResize(setCartHeight);
    useEffect(setCartHeight);

    const componentVariables = {
        'cart-overlay-height': cartMaxHeight && `${cartMaxHeight}px`
    };

    const { items: cartItems } = cart || {};
    const i18nWithDefaults = { ...HeaderCartOverlay.defaultProps.i18n, ...i18n };
    const { cart: i18nCartBase } = i18nWithDefaults;
    const i18nCart = {
        ...HeaderCartOverlay.defaultProps.i18n.cart,
        ...i18nCartBase
    };
    const hasCartItems = Boolean(cartItems && cartItems.length);
    const isCartActive = isLoggedIn && hasCartItems;

    const showFooter = !isLoggedIn || isCartActive;

    const wrapperModifers = [
        isLoading && 'is-loading'
    ];

    const cartModifiers = [isCartActive && 'active'];
    const contentModifiers = [
        !showFooter && 'no-footer',
        isScrollEnabled && 'with-scrollbar'
    ];

    const viewCartPage = () => {
        window.location.pathname = CART_URL;
    };

    const renderCartItem = ({ itemDetails: editionDetails, childItems: addonItems }) => {
        if (!editionDetails) {
            return null;
        }

        const { id, branding: { name } } = editionDetails;

        return (
            <div {...n('product').withTestId().props} key={generateUniqueID([id, name])}>
                <div {...n('edition').withTestId().props}>
                    <CartEditionPreview {...editionDetails} i18n={i18nCart} variant="cart-overlay" />
                </div>
                {Boolean(addonItems && addonItems.length) && (
                    <div {...n('addonList').props}>
                        {addonItems.map(renderAddon)}
                    </div>
                )}
            </div>
        );
    };

    const renderCloseButton = (
        <ButtonIcon
            {...n('close').props}
            icon="close"
            type="icon"
            hiddenText
            theme={THEME_SECONDARY}
            onClick={onClose}
        >
            {i18nCart.close}
        </ButtonIcon>
    );

    const renderLoading = (
        <div {...n('loading').withTestId().props}>
            <Preloader {...n('preloader').props} isLoading />
            {renderCloseButton}
        </div>
    );

    const renderCartHeader = (
        <div {...n('header').props}>
            <span {...n('title').props} id={titleId}>
                {hasNewProductAdded ? (
                    <>
                        <Icon {...n('titleIcon').props} type="check" />
                        {i18nCart.addedToCart}
                    </>
                ) : i18nCart.cartSummary}
            </span>
            {renderCloseButton}
        </div>
    );

    const renderCartFooter = () => {
        const footerModifiers = [isScrollEnabled && 'with-box-shadow'];
        const buttonProps = {
            ...n('footerButton').props,
            theme: THEME_PRIMARY,
            onClick: viewCartPage
        };

        return (
            <div {...n('footer', footerModifiers).props}>
                {!isLoggedIn && (
                    <ButtonIcon {...buttonProps}>{i18nWithDefaults['sign.in']}</ButtonIcon>
                )}
                {isCartActive && (
                    <ButtonIcon {...buttonProps}>{i18nCart.viewCart}</ButtonIcon>
                )}
            </div>
        );
    };

    const renderCartContent = (
        <>
            <div {...n('content', contentModifiers).props}>
                <div {...n('cart', cartModifiers).props} id={contentId}>
                    {addToCartError && (
                        <div {...n('message', 'error').withTestId().props}>
                            <Icon type="caution" {...n('messageIcon', 'error').props} />
                            <span {...n('messageText').props}>{i18nCart.addToCartError}</span>
                        </div>
                    )}
                    {!addToCartError && alreadyInCartNotif && (
                        <div {...n('message', 'success').withTestId().props}>
                            <Icon type="check" {...n('messageIcon', 'success').props} />
                            <span {...n('messageText').props}>{i18nCart.alreadyInCart}</span>
                        </div>
                    )}
                    {isCartActive ? cartItems.map(renderCartItem) : (
                        <div {...n('cartEmpty').props}>
                            <span {...n('cartTitle').props}>{i18nCart.emptyCart.title}</span>
                            {!isLoggedIn && (
                                <p {...n('cartDescription').props}>{i18nCart.emptyCart['sign.in']}</p>
                            )}
                        </div>
                    )}
                </div>
            </div>
            {showFooter && renderCartFooter()}
        </>
    );

    return (
        <div
            {...n('wrapper', wrapperModifers).withVariables(componentVariables).withClass(className).withTestId().props}
            role="dialog"
            aria-modal="true"
            aria-labelledby={titleId}
            aria-describedby={contentId}
            onMouseLeave={onMouseLeave}
            onMouseOver={onMouseOver}
            onFocus={onFocus}
        >
            <div {...n('mask').props}>
                <div {...n('main', isLoading && 'is-loading').props} ref={setCartRef}>
                    {isLoading ? renderLoading : (
                        <>
                            {renderCartHeader}
                            {renderCartContent}
                        </>
                    )}
                </div>
            </div>
        </div>
    );
};

HeaderCartOverlay.propTypes = {
    cart: PropTypes.shape(cartShape),
    isLoggedIn: PropTypes.bool,
    isLoading: PropTypes.bool,
    hasNewProductAdded: PropTypes.bool,
    className: PropTypes.string,
    i18n: PropTypes.shape({
        'sign.in': PropTypes.string,
        cart: PropTypes.shape({
            addedToCart: PropTypes.string,
            cartSummary: PropTypes.string,
            viewCart: PropTypes.string,
            close: PropTypes.string,
            addToCartError: PropTypes.string,
            alreadyInCart: PropTypes.string,
            emptyCart: PropTypes.shape({
                title: PropTypes.string,
                'sign.in': PropTypes.string
            })
        })
    }),
    addToCartError: PropTypes.bool,
    alreadyInCartNotif: PropTypes.bool,
    onClose: PropTypes.func,
    onMouseLeave: PropTypes.func,
    onMouseOver: PropTypes.func,
    onFocus: PropTypes.func,
    cartRefCallback: PropTypes.func
};

HeaderCartOverlay.defaultProps = {
    cart: null,
    isLoggedIn: false,
    isLoading: false,
    hasNewProductAdded: false,
    className: null,
    i18n: {
        'sign.in': 'Sign in',
        cart: {
            addedToCart: 'Added to Cart',
            cartSummary: 'Cart Summary',
            viewCart: 'View Cart',
            close: 'Close the cart summary',
            addToCartError: 'We were unable to add this item to your cart. Please refresh the page and try again.',
            alreadyInCart: 'This item is already in your cart.',
            emptyCart: {
                title: 'Your cart is empty.',
                'sign.in': 'Sign in to see items you may have added to your cart during a previous visit.'
            }
        }
    },
    addToCartError: false,
    alreadyInCartNotif: false,
    cartRefCallback: () => {},
    onClose: () => {},
    onMouseLeave: () => {},
    onMouseOver: () => {},
    onFocus: () => {}
};

export default HeaderCartOverlay;
