import React, { useRef, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import Slick from 'react-slick';

import withListener from '../withListener';
import Icon from '../../atoms/icon/Icon';
import CarouselSlideText, { TEXT_SLIDE_TYPE, PRODUCT_TYPE } from '../../atoms/carousel-slide-text/CarouselSlideText';
import CarouselSlideImage, { IMAGE_SLIDE_TYPE } from '../../atoms/carousel-slide-image/CarouselSlideImage';
import CarouselSlideVideo, { VIDEO_SLIDE_TYPE } from '../../atoms/carousel-slide-video/CarouselSlideVideo';
import { TOGGLE_CHECK, GROUP_HEADER, DROPDOWN, RADIO, COLORPICKER, IMAGE_UPLOADER, SLIDES } from '../../constants/schemaComponentTypes';
import { NAMESPACES } from '../../constants/namespaces';
import { BACKGROUND_COLOR, BACKGROUND_IMAGE } from '../../constants/backgroundSettings';

import './styles/Carousel.scss';
import { createNamespace } from '../../tools/namingTools';
import { parseProductSlide } from '../../tools/slidesParser';
import { generateUniqueID } from '../../tools/helpers';

const DELAY_OPTIONS = [
    { value: 3, label: '3 seconds' },
    { value: 4, label: '4 seconds' },
    { value: 5, label: '5 seconds' },
    { value: 7, label: '7 seconds' },
    { value: 10, label: '10 seconds' },
    { value: 15, label: '15 seconds' }
];
const HEIGHT_OPTIONS = [
    { value: 400, label: 'Small 400px' },
    { value: 555, label: 'Medium 555px' },
    { value: 660, label: 'Large 660px' }
];

const COLOR_DARK = 'uieditor.sfbComponent.carousel.caretsColorTheme.dark';
const COLOR_LIGHT = 'uieditor.sfbComponent.carousel.caretsColorTheme.light';
const CARETS_COLOR_OPTIONS = [
    { value: COLOR_DARK, label: COLOR_DARK },
    { value: COLOR_LIGHT, label: COLOR_LIGHT }
];

const defaultSlide = [{
    contentType: 'IMAGE_ONLY',
    slideData: {
        backgroundColor: '#F4F4F4',
        image: {},
        imageSizing: 'fill',
        slideLink: null,
        slideName: '',
        text: '',
        textColor: '#fff',
        textOverlay: false,
        textSize: 'small',
        title: ''
    }
}];

// on mobile, the height of carousel is a smaller proportion of the desired height
const MOBILE_HEIGHT_RATIO = 0.75;

const n = createNamespace('Carousel');

const SLIDE_COMPONENT = {
    [IMAGE_SLIDE_TYPE]: CarouselSlideImage,
    [VIDEO_SLIDE_TYPE]: CarouselSlideVideo,
    [TEXT_SLIDE_TYPE]: CarouselSlideText,
    [PRODUCT_TYPE]: CarouselSlideText
};

export const CarouselComponent = ({ data: { i18n }, settings, isPreviewMode = false }) => {
    const settingsWithDefaults = { ...CarouselComponent.defaultProps.settings, ...settings };
    const { caretsColorTheme, isAutorotate, slides } = settingsWithDefaults;
    const caretsColor = caretsColorTheme === COLOR_DARK ? 'black' : 'white';
    const i18nWithDefaults = { ...CarouselComponent.defaultProps.data.i18n, ...i18n };
    const sliderRef = useRef(null);

    const goToPrev = useCallback(() => {
        if (isPreviewMode) {
            return;
        }
        sliderRef.current.slickPrev();
    }, [isPreviewMode]);

    const goToNext = useCallback(() => {
        if (isPreviewMode) {
            return;
        }
        sliderRef.current.slickNext();
    }, [isPreviewMode]);

    useEffect(() => {
        if (Number.isInteger(isPreviewMode) && isPreviewMode >= 0) {
            sliderRef.current.slickGoTo(isPreviewMode);
            sliderRef.current.slickPause();
        } else if (isAutorotate) {
            sliderRef.current.slickPlay();
        }
    }, [isAutorotate, isPreviewMode]);

    const mobileHeight = Math.ceil(MOBILE_HEIGHT_RATIO * settingsWithDefaults.height);
    const slideSettings = {
        ...settingsWithDefaults,
        mobileHeight
    };

    const renderItem = item => {
        const uid = generateUniqueID([item.slideData.title, item.slideData.text]);
        const ComponentConstructor = SLIDE_COMPONENT[item.contentType || TEXT_SLIDE_TYPE];
        const itemSettings = item.contentType === PRODUCT_TYPE ? parseProductSlide(item.slideData) : item.slideData;

        return (
            <div {...n('slide').withTestId().withE2EId().props} key={uid}>
                <ComponentConstructor data={itemSettings} settings={slideSettings} />
            </div>
        );
    };

    const renderSlides = () => {
        if (!slides.length) {
            return defaultSlide.map(renderItem);
        }
        return slides.map(renderItem);
    };

    const { backgroundType, backgroundColor, backgroundImg } = settingsWithDefaults;
    const componentVariables = {
        'background-color': backgroundType === BACKGROUND_COLOR.value ? backgroundColor : null,
        'background-image': backgroundType === BACKGROUND_IMAGE.value ? backgroundImg && `url(${backgroundImg.url})` : null,
        'carets-color': caretsColor,
        height: `${settingsWithDefaults.height}px`,
        'mobile-height': `${mobileHeight}px`
    };

    const wrapperModifiers = [settingsWithDefaults.isDisplayDots && 'with-dots'];

    const arrowModifiers = settingsWithDefaults.isDisplayCaretsOnHover && 'showOnHover';

    return (
        <div {...n('wrapper', wrapperModifiers).withTestId().withVariables(componentVariables).withE2EId().props}>
            <div {...n('content').withE2EId().props}>
                <Slick
                    ref={sliderRef}
                    slidesToShow={1}
                    dots={settingsWithDefaults.isDisplayDots}
                    arrows={false}
                    autoplay={isAutorotate}
                    autoplaySpeed={settingsWithDefaults.delay * 1000}
                    slickPause={isPreviewMode}
                    speed={450}
                    draggable={false}
                    infinite
                >
                    {renderSlides()}
                </Slick>
                {settingsWithDefaults.isDisplayCarets && (
                    <React.Fragment>
                        <button {...n('arrow', [arrowModifiers, 'prev']).withTestId().withE2EId('prev').props} type="button" onClick={goToPrev}>
                            <Icon type="caretLeft" {...n('arrowIcon').withE2EId('prev').props} />
                            <span {...n('arrowText').withE2EId('prev').props}>{i18nWithDefaults.previous}</span>
                        </button>
                        <button {...n('arrow', [arrowModifiers, 'next']).withTestId('next').props} type="button" onClick={goToNext}>
                            <Icon type="caretRight" {...n('arrowIcon').withE2EId('next').props} />
                            <span {...n('arrowText').withE2EId('next').props}>{i18nWithDefaults.next}</span>
                        </button>
                    </React.Fragment>
                )}
            </div>
        </div>
    );
};

const BACKGROUND_TYPE_OPTIONS = [BACKGROUND_IMAGE, BACKGROUND_COLOR];

CarouselComponent.schema = () => ({
    name: 'Carousel',
    title: 'uieditor.sfbComponent.carousel.title',
    iconName: 'carousel',
    orderableSection: [
        NAMESPACES.home, NAMESPACES.listing, NAMESPACES.profile, NAMESPACES.profileEdition,
        NAMESPACES.profileFeatures, NAMESPACES.bundle, NAMESPACES.help
    ],
    form: {
        slides: {
            type: SLIDES
        },
        headingSpacer: {
            type: GROUP_HEADER,
            title: 'uieditor.sfbComponent.carousel.settings.title',
            symbol: 'style'
        },
        height: {
            title: 'uieditor.sfbComponent.carousel.height.title',
            type: DROPDOWN,
            required: false,
            defaultValue: HEIGHT_OPTIONS[1].value,
            options: HEIGHT_OPTIONS,
            validation: {
                availableOptions: HEIGHT_OPTIONS.map(({ value }) => value),
                message: 'uieditor.sfbComponent.dropdown.validation.message',
                default: 'uieditor.sfbComponent.dropdown.defaultValue'
            }
        },

        backgroundType: {
            title: 'uieditor.sfbComponent.carousel.backgroundType.title',
            type: RADIO,
            required: false,
            defaultValue: BACKGROUND_TYPE_OPTIONS[1].value,
            options: BACKGROUND_TYPE_OPTIONS,
            validation: {
                availableOptions: BACKGROUND_TYPE_OPTIONS.map(({ value }) => value),
                message: 'uieditor.sfbComponent.radio.validation.message',
                default: 'uieditor.sfbComponent.dropdown.defaultValue'
            }
        },
        backgroundImg: {
            title: 'uieditor.sfbComponent.carousel.backgroundImg.title',
            caption: 'uieditor.sfbComponent.carousel.backgroundImg.caption',
            placeholder: 'uieditor.sfbComponent.carousel.backgroundImg.placeholder',
            defaultValue: {},
            type: IMAGE_UPLOADER,
            required: false,
            conditionalAttributes: {
                isDisabled: {
                    when: 'backgroundType',
                    connector: 'equals',
                    value: BACKGROUND_COLOR.value
                }
            }
        },
        backgroundColor: {
            title: 'uieditor.sfbComponent.carousel.backgroundColor.title',
            defaultValue: '#fff',
            type: COLORPICKER,
            conditionalAttributes: {
                isDisabled: {
                    when: 'backgroundType',
                    connector: 'equals',
                    value: BACKGROUND_IMAGE.value
                }
            }
        },
        isDisplayCarets: {
            label: 'uieditor.sfbComponent.carousel.isDisplayCarets.label',
            defaultValue: true,
            type: TOGGLE_CHECK,
            marginSize: 10
        },
        isDisplayCaretsOnHover: {
            label: 'uieditor.sfbComponent.carousel.isDisplayCaretsOnHover.label',
            defaultValue: false,
            type: TOGGLE_CHECK,
            conditionalAttributes: {
                isVisible: {
                    when: 'isDisplayCarets',
                    connector: 'equals',
                    value: true
                }
            },
            indentSize: 1,
            marginSize: 10
        },
        isDisplayDots: {
            label: 'uieditor.sfbComponent.carousel.isDisplayDots.label',
            defaultValue: true,
            type: TOGGLE_CHECK
        },
        caretsColorTheme: {
            title: 'uieditor.sfbComponent.carousel.caretsColorTheme.title',
            type: DROPDOWN,
            required: false,
            defaultValue: CARETS_COLOR_OPTIONS[1].value,
            options: CARETS_COLOR_OPTIONS,
            validation: {
                availableOptions: CARETS_COLOR_OPTIONS.map(({ value }) => value),
                message: 'uieditor.sfbComponent.dropdown.validation.message',
                default: 'uieditor.sfbComponent.dropdown.defaultValue'
            }
        },
        isAutorotate: {
            label: 'uieditor.sfbComponent.carousel.isAutorotate.label',
            defaultValue: true,
            type: TOGGLE_CHECK
        },
        delay: {
            title: 'uieditor.sfbComponent.carousel.delay.title',
            type: DROPDOWN,
            required: false,
            defaultValue: DELAY_OPTIONS[2].value,
            options: DELAY_OPTIONS,
            validation: {
                availableOptions: DELAY_OPTIONS.map(({ value }) => value),
                message: 'uieditor.sfbComponent.dropdown.validation.message',
                default: 'uieditor.sfbComponent.dropdown.defaultValue'
            },
            conditionalAttributes: {
                isVisible: {
                    when: 'isAutorotate',
                    connector: 'equals',
                    value: true
                }
            }
        }
    }
});

CarouselComponent.propTypes = {
    data: PropTypes.shape({
        i18n: PropTypes.shape({
            learnMore: PropTypes.string,
            previous: PropTypes.string,
            next: PropTypes.string
        })
    }),
    settings: PropTypes.shape({
        slides: PropTypes.arrayOf(
            PropTypes.shape({
                name: PropTypes.string,
                blurb: PropTypes.string,
                url: PropTypes.string,
                overviewImageUrl: PropTypes.string
            })
        ),
        height: PropTypes.number,
        isDisplayCarets: PropTypes.bool,
        caretsColorTheme: PropTypes.string,
        isDisplayCaretsOnHover: PropTypes.bool,
        isDisplayDots: PropTypes.bool,
        isAutorotate: PropTypes.bool,
        delay: PropTypes.number,
        backgroundColor: PropTypes.string,
        backgroundImg: PropTypes.shape({
            filename: PropTypes.string,
            type: PropTypes.oneOf([IMAGE_UPLOADER]),
            url: PropTypes.string
        })
    }),
    isPreviewMode: PropTypes.bool
};

const SETTINGS = CarouselComponent.schema().form;
CarouselComponent.defaultProps = {
    data: {
        i18n: {
            learnMore: 'Learn More',
            previous: 'Previous',
            next: 'Next'
        }
    },
    settings: {
        slides: [],
        height: SETTINGS.height.defaultValue,
        isDisplayCarets: SETTINGS.isDisplayCarets.defaultValue,
        caretsColorTheme: SETTINGS.caretsColorTheme.defaultValue,
        isDisplayCaretsOnHover: SETTINGS.isDisplayCaretsOnHover.defaultValue,
        isDisplayDots: SETTINGS.isDisplayDots.defaultValue,
        isAutorotate: SETTINGS.isAutorotate.defaultValue,
        delay: SETTINGS.delay.defaultValue,
        backgroundColor: SETTINGS.backgroundColor.defaultValue,
        backgroundImg: null
    },
    isPreviewMode: false
};

export default withListener(CarouselComponent);
