import React, { useState, useMemo } from 'react';
import PropTypes from 'prop-types';
import withListener from '../withListener';
import { createNamespace } from '../../tools/namingTools';
import { bSmall, bMedium, bXLarge } from '../../constants/breakpoints';
import { useContainerWidth } from '../../tools/widths/useContainerWidth';
import { KEY_CODE } from '../../constants/keyCodes';
import SlickSlider from '../../atoms/slick-slider/SlickSlider';
import ProductTopFeatures, { topFeatureOverviewShape } from '../product-top-features/TopFeatures';
import BundleSummary, { bundleSummaryShape } from '../bundle-summary/BundleSummary';
import BundleCard, { bundleCardShape, bundlePricingShape } from '../../atoms/bundle-card/BundleCard';
import './styles/ProductBundles.scss';

const n = createNamespace('ProductBundles');

export const getSelectedBundleId = bundles => {
    // Set Initial Bundle to be selected based on 'focused' property
    const focusedBundle = bundles.find(item => item.focused);

    return focusedBundle ? focusedBundle.id : bundles[0].id;
};

export const getBundlePricing = (currentEdition, pricingEditions) => {
    if (!currentEdition) {
        return null;
    }

    const pricingMatchProperty = 'name';

    return pricingEditions && pricingEditions.length ? pricingEditions.find(
        pricingEdition => pricingEdition[pricingMatchProperty] === currentEdition[pricingMatchProperty]
    ) : null;
};

const getSlideToShow = containerWidth => {
    if (containerWidth < bSmall) {
        return 1;
    }
    if (containerWidth < bMedium) {
        return 2;
    }
    if (containerWidth < bXLarge) {
        return 3;
    }

    return 4;
};

export const ProductBundlesComponent = ({
    data: {
        items,
        summary,
        pricing,
        i18n
    }
}) => {
    const [containerRef, containerWidth] = useContainerWidth();

    const carouselSlidesToShow = getSlideToShow(containerWidth);

    const [selectedId, setSelectedId] = useState(() => {
        if (!items || !items.length) {
            return null;
        }

        return getSelectedBundleId(items);
    });

    // Add pricing informations inside bundle's item children
    const bundleList = useMemo(() => items && items.reduce((accumulator, currentValue) => {
        accumulator[currentValue.id] = {
            ...currentValue,
            pricing: pricing ? getBundlePricing(currentValue.edition, pricing.editions) : null
        };

        return accumulator;
    }, {}), [items, pricing]);

    // Build array of bundle's ID as keys for the map function
    const bundleKeyList = bundleList ? Object.keys(bundleList) : [];

    // Render empty component if no bundles
    if (!bundleKeyList || !bundleKeyList.length) {
        return null;
    }

    const handleClick = clickedBundleId => {
        setSelectedId(clickedBundleId);
    };

    const handleKeypress = (e, bundleId) => {
        if (e.charCode === KEY_CODE.return) {
            handleClick(bundleId);
        }
    };

    const navigateToSlide = newIndex => {
        if (newIndex !== null || newIndex !== 'undefined') {
            const newBundle = bundleList[bundleKeyList[newIndex]];

            setSelectedId(newBundle.id);
        }
    };

    const renderBundleCard = bundle => {
        const isSelected = selectedId === bundle.id;

        return (
            <div {...n('card').withTestId().props} key={bundle.name}>
                <div
                    {...n('bundle', isSelected && 'selected').withTestId().props}
                    role="button"
                    tabIndex="0"
                    onClick={() => handleClick(bundle.id)}
                    onKeyPress={e => handleKeypress(e, bundle.id)}
                >
                    <BundleCard data={{ ...bundle }} />
                </div>
            </div>
        );
    };

    const slickInitialSlide = bundleKeyList.findIndex(key => Number(key) === selectedId);

    const sliderSettings = {
        swipe: true,
        draggable: false,
        infinite: false,
        initialSlide: slickInitialSlide,
        slidesToShow: carouselSlidesToShow,
        afterChange: navigateToSlide
    };

    return (
        <div {...n('container').props} ref={containerRef}>
            <h1 {...n('title').props} id="bundleTitle">{summary.title}</h1>
            <div {...n('tab', bundleKeyList.length > carouselSlidesToShow && 'with-arrows').props}>
                <SlickSlider settings={sliderSettings}>
                    {bundleKeyList.map(key => renderBundleCard(bundleList[key]))}
                </SlickSlider>
            </div>
            {selectedId && (
                <div {...n('panel').props}>
                    <div {...n('summary').props}>
                        <BundleSummary data={{ ...bundleList[selectedId], i18n }} />
                    </div>
                    <div {...n('features').props}>
                        <ProductTopFeatures data={bundleList[selectedId]} />
                    </div>
                </div>
            )}
        </div>
    );
};

ProductBundlesComponent.schema = () => ({
    name: 'ProductBundles',
    title: 'uieditor.sfbComponent.productBundles.title',
    iconName: '',
    form: {},
    marketplaceData: {
        summary: 'bundle.summary',
        pricing: 'bundle.pricing',
        i18n: 'bundle.i18n',
        items: 'bundle.items'
    }
});

ProductBundlesComponent.propTypes = {
    data: PropTypes.shape({
        summary: PropTypes.shape({
            title: PropTypes.string,
            description: PropTypes.string,
            images: PropTypes.arrayOf(PropTypes.string)
        }),
        pricing: PropTypes.shape({
            editions: PropTypes.arrayOf(PropTypes.shape(bundlePricingShape))
        }),
        i18n: PropTypes.shape({
            viewProduct: PropTypes.string,
            pricing: PropTypes.string,
            demo: PropTypes.string
        }),
        items: PropTypes.arrayOf(PropTypes.shape({
            id: PropTypes.number,
            focused: PropTypes.bool,
            card: PropTypes.shape(bundleCardShape),
            overview: PropTypes.shape({
                ...bundleSummaryShape,
                ...topFeatureOverviewShape
            })
        }))
    })
};

ProductBundlesComponent.defaultProps = {
    data: {
        summary: {
            title: 'Super Bundle',
            description: 'Bundle',
            images: []
        },
        pricing: {
            editions: []
        },
        i18n: {
            viewProduct: 'View Product',
            pricing: 'Pricing',
            demo: 'Demo'
        },
        items: []
    }
};

export default withListener(ProductBundlesComponent);
