import React, { useState, useMemo, useRef } 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 { i18nPropTypes } from '../../constants/prop-types/bundle/i18n';
import { itemPropTypes } from '../../constants/prop-types/bundle/items';
import { useCarouselA11yVisible } from '../../tools/a11y/useCarouselA11yVisible';
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 { LEFT, RIGHT } from '../../constants/alignment';
import { DROPDOWN, COLORPICKER, RADIO, TOGGLE } from '../../constants/schemaComponentTypes';
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 = (productName, editionName, pricingEditions) => {
    if (!productName || !editionName) {
        return null;
    }

    return pricingEditions && pricingEditions.length ? pricingEditions.find(
        pricingEdition => pricingEdition.productName === productName && pricingEdition.name === editionName
    ) : null;
};

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

    return 4;
};

const BundleCardButton = ({
    bundle,
    isSelected,
    handleClick,
    handleKeypress,
    i18n
}) => {
    const containerRef = useRef();
    const [, tabIndex] = useCarouselA11yVisible(containerRef);

    return (
        <div {...n('card').withTestId().props} aria-label={bundle.name} ref={containerRef}>
            <button
                type="button"
                tabIndex={tabIndex}
                {...n('cardButton').withTestId().props}
                onClick={() => handleClick(bundle.id)}
                onKeyPress={e => handleKeypress(e, bundle.id)}
            >
                <span {...n('cardButtonText').withTestId().props}>{i18n.clickBundleSummary}</span>
            </button>
            <BundleCard
                {...n('bundle', [isSelected && 'selected']).withTestId().props}
                {...bundle}
                i18n={i18n}
            />
        </div>
    );
};

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

    const { tileHighlightColor,
        featuresBackgroundColor,
        imagePosition,
        isDisplayShadow,
        shadowFill,
        numberOfColumns } = settingsWithDefaults;

    const summarySettings = {
        imagePosition,
        isDisplayShadow,
        shadowFill
    };

    const cssVariables = { ...tileHighlightColor && {
        'tile-highlight-color': tileHighlightColor
    },
    ...featuresBackgroundColor && {
        'bundle-features-bg-color': featuresBackgroundColor
    } };

    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.name, currentValue.edition?.name, 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 i18nWithDefaults = { ...ProductBundlesComponent.defaultProps.data.i18n, ...i18n };

    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 => (
        <BundleCardButton
            key={bundle.name}
            isSelected={selectedId === bundle.id}
            handleKeypress={handleKeypress}
            handleClick={handleClick}
            bundle={bundle}
            i18n={i18nWithDefaults}
        />
    );

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

    const sliderSettings = {
        swipe: true,
        accessibility: true,
        draggable: false,
        infinite: false,
        initialSlide: slickInitialSlide,
        slidesToShow: carouselSlidesToShow,
        afterChange: navigateToSlide
    };
    return (
        <section {...n('container').withVariables(cssVariables).props} ref={containerRef}>
            <h2 {...n('title').props} id="bundleTitle">{summary.title}</h2>
            <div {...n('sliderMask').props}>
                <div className="container">
                    <div {...n('tab', bundleKeyList.length > carouselSlidesToShow && 'with-arrows').props}>
                        <SlickSlider settings={sliderSettings} i18n={i18nWithDefaults}>
                            {bundleKeyList.map(key => renderBundleCard(bundleList[key]))}
                        </SlickSlider>
                    </div>
                    {selectedId && (
                        <div {...n('panel').props}>
                            <div {...n('summary').props}>
                                <BundleSummary
                                    data={{ ...bundleList[selectedId], i18n }}
                                    settings={summarySettings}
                                />
                            </div>
                            <div {...n('features').props}>
                                <ProductTopFeatures data={bundleList[selectedId]} settings={{ numberOfColumns }} />
                            </div>
                        </div>
                    )}
                </div>
            </div>
        </section>
    );
};

const IMAGE_POSITION_OPTIONS = [LEFT, RIGHT];
const NUMBER_COLUMNS_OPTIONS = [
    { value: 'one', label: 'uieditor.sfbComponent.productBundles.numberOfColumns.option.one' },
    { value: 'two', label: 'uieditor.sfbComponent.productBundles.numberOfColumns.option.two' },
    { value: 'three', label: 'uieditor.sfbComponent.productBundles.numberOfColumns.option.three' }
];

BundleCardButton.propTypes = {
    bundle: PropTypes.shape(itemPropTypes),
    i18n: PropTypes.shape(i18nPropTypes),
    isSelected: PropTypes.bool,
    handleKeypress: PropTypes.func,
    handleClick: PropTypes.func
};
BundleCardButton.defaultProps = {
    bundle: {},
    isSelected: false,
    handleKeypress: () => {},
    handleClick: () => {},
    i18n: {}
};

ProductBundlesComponent.schema = () => ({
    name: 'ProductBundles',
    title: 'uieditor.sfbComponent.productBundles.title',
    iconName: 'slider',
    form: {
        tileHighlightColor: {
            title: 'uieditor.sfbComponent.productBundles.tileHighlightColor.title',
            type: COLORPICKER
        },
        featuresBackgroundColor: {
            title: 'uieditor.sfbComponent.productBundles.featuresBackgroundColor.title',
            type: COLORPICKER
        },
        imagePosition: {
            title: 'uieditor.sfbComponent.productBundles.imagePosition.title',
            type: RADIO,
            required: true,
            defaultValue: IMAGE_POSITION_OPTIONS[1].value,
            options: IMAGE_POSITION_OPTIONS
        },
        isDisplayShadow: {
            labelOn: 'uieditor.sfbComponent.productBundles.isDisplayShadow.labelOn',
            labelOff: 'uieditor.sfbComponent.productBundles.isDisplayShadow.labelOff',
            defaultValue: false,
            type: TOGGLE
        },
        shadowFill: {
            title: 'uieditor.sfbComponent.productBundles.shadowFill.title',
            type: COLORPICKER
        },
        numberOfColumns: {
            title: 'uieditor.sfbComponent.productBundles.numberOfColumns.title',
            type: DROPDOWN,
            defaultValue: NUMBER_COLUMNS_OPTIONS[1].value,
            options: NUMBER_COLUMNS_OPTIONS
        }
    },
    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
            })
        }))
    }),
    settings: PropTypes.shape({
        tileHighlightColor: PropTypes.string,
        featuresBackgroundColor: PropTypes.string,
        imagePosition: PropTypes.oneOf(IMAGE_POSITION_OPTIONS),
        isDisplayShadow: PropTypes.bool,
        shadowFill: PropTypes.string,
        numberOfColumns: PropTypes.oneOf(NUMBER_COLUMNS_OPTIONS)
    })
};

ProductBundlesComponent.defaultProps = {
    data: {
        summary: {
            title: 'Super Bundle',
            description: 'Bundle',
            images: []
        },
        pricing: {
            editions: []
        },
        i18n: {
            viewProduct: 'View Product',
            pricing: 'Pricing',
            demo: 'Demo'
        },
        items: []
    },
    settings: {
        tileHighlightColor: null,
        featuresBackgroundColor: '#F4F4F4',
        imagePosition: RIGHT,
        isDisplayShadow: false,
        shadowFill: '#FFFFFF',
        numberOfColumns: NUMBER_COLUMNS_OPTIONS[1].value
    }
};

export default withListener(ProductBundlesComponent);
