import React from 'react';
import PropTypes from 'prop-types';
import DOMPurify from 'dompurify';

import { createNamespace } from '../../tools/namingTools';
import { lowerFirst } from '../../tools/stringTools';
import { parseToBool } from '../../tools/helpers';
import { darken } from '../../tools/colorHelper';
import { useResponsive } from '../../tools/widths/useResponsive';

import { PRODUCT_DEFAULT_IMG } from '../../constants/images';
import { SLIDER, COLORPICKER, TOGGLE, DROPDOWN } from '../../constants/schemaComponentTypes';
import { SMALL, MEDIUM } from '../../constants/sizes';
import { GRID_VIEW, LIST_VIEW } from '../../constants/views';
import { itemsPropTypes as productListingCardShape } from '../../constants/prop-types/listingProducts/items';
import { i18nPropTypes } from '../../constants/prop-types/listingProducts/i18n';

import Badge from '../badge/Badge';
import Checkbox from '../checkbox/Checkbox';
import Pricing from '../pricing/Pricing';
import Rating from '../rating/Rating';
import Image from '../image/Image';

import { ListingLoader, GridLoader } from '../../tools/LoaderSchema';

import { PRODUCT_LISTING_CARD_MAX_MERCHANDISING_BADGES } from '../../constants/components/product-listing-card';
import { renderBadge } from '../../tools/rendering/merchandisingBadges';

import './styles/ProductListingCard.scss';

const n = createNamespace('ProductListingCard');

const ProductListingCard = ({
    data: {
        id,
        name,
        blurb,
        overview,
        vendorName,
        url,
        hidePricings,
        iconUrl,
        iconAlt,
        iconSrcset = {},
        version,
        badges = [],
        rating,
        numRatings,
        ratingCaption,
        startingPrice,
        productRibbon,
        free,
        merchandisingBadges
    },
    showAsGrid,
    onCheckCompare,
    isCompareChecked,
    isDisabled,
    isLoading,
    i18n: i18nProp,
    settings
}) => {
    const i18n = { ...ProductListingCard.defaultProps.i18n, ...i18nProp };
    const {
        iconSize,
        borderRadius,
        titleColor,
        headerBackgroundColor,
        backgroundColor,
        borderColor,
        isCompareVisible,
        isRatingsVisible,
        isVendorVisible,
        isBlurbVisible,
        isOverviewVisible
    } = { ...ProductListingCard.defaultProps.settings, ...settings };

    const { mediumDown } = useResponsive();
    const isMobile = mediumDown;

    const viewMode = showAsGrid ? GRID_VIEW : LIST_VIEW;
    const containerModifiers = [viewMode];
    const imageContainerModifiers = [lowerFirst(iconSize)];

    const [showRatings] = parseToBool(isRatingsVisible);
    const [showCompareBtn] = parseToBool(isCompareVisible);

    const shouldRenderRating = !!(showRatings && !!rating && numRatings > 0);

    // Variables used in the SCSS file, to keep all styles in css
    const componentVariables = Object.assign({}, backgroundColor && {
        'card-container-bg-color': backgroundColor,
        'card-container-bg-color-hover': darken(backgroundColor, 0.05)
    }, headerBackgroundColor && showAsGrid && {
        'card-header-bg-color': headerBackgroundColor,
        'card-header-bg-color-hover': darken(headerBackgroundColor, 0.05)
    }, titleColor && {
        'card-title-color': titleColor
    }, borderColor && {
        'card-border-color': borderColor
    }, borderRadius && {
        'card-border-radius': `${borderRadius}px`
    }, productRibbon && {
        'card-ribbon-color': productRibbon.textColor,
        'card-ribbon-bg-color': productRibbon.ribbonColor
    });

    const getLoader = () => {
        if (showAsGrid) {
            return <GridLoader />;
        }
        return <ListingLoader />;
    };

    // Render Blocks
    const imageBlock = (
        <Image
            src={iconUrl || ProductListingCard.defaultProps.data.iconUrl}
            srcSet={iconSrcset}
            alt={iconAlt || name}
            className={n('icon').props.className}
        />
    );

    const versionBlock = version && (
        <span {...n('version').withTestId().props}>{`${i18n.version} ${version}`}</span>
    );

    const vendorNameBlock = isVendorVisible && vendorName && (
        <span {...n('vendor').withTestId().props}>{`${i18n.soldBy} ${vendorName}`}</span>
    );

    const merchandisingBadgesDisplay = merchandisingBadges && merchandisingBadges.length ? (
        <ul {...n('productBadges').withTestId().props} aria-label={i18n.merchandisingBadges}>
            {merchandisingBadges.slice(0, PRODUCT_LISTING_CARD_MAX_MERCHANDISING_BADGES).map(badge => (
                <li {...n('productBadgesItem').props} key={badge.uuid}>
                    {renderBadge(badge)}
                </li>
            ))}
        </ul>
    ) : '';

    const promoBadges = (
        <ul {...n('promoBadges', !showAsGrid && 'list').props} aria-label={i18n.badges}>
            {badges.map((badge, index) => {
                const badgeId = badge.id ? `${id}-${badge.id}-${index}` : `${id}-${index}`;
                const badgeProps = { ...badge, ...{ id: badgeId } };

                return (
                    <li {...n('badgeWrapper').props} key={badgeId}>
                        <Badge {...n('promoBadge').withTestId().props} {...badgeProps} />
                    </li>
                );
            })}
        </ul>
    );

    const blurbBlock = isBlurbVisible && (
        <div {...n('caption').withTestId().props}>{blurb}</div>
    );

    const overviewBlock = isOverviewVisible && (
        <div {...n('overview').withTestId().props} dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(overview) }} />
    );

    const badgeBlock = badges && badges.length ? (
        <div {...n('badges').withTestId().props}>
            {merchandisingBadgesDisplay}
            {promoBadges}
        </div>
    ) : '';

    const badgeBlockGrid = badges && badges.length ? (
        <div {...n('badges').withTestId().props}>
            {promoBadges}
        </div>
    ) : '';

    const ribbonBlock = productRibbon && (
        <div {...n('ribbon').withTestId().props}>
            {productRibbon.text}
        </div>
    );

    const tagsBlock = (ribbonBlock || badgeBlock) && (
        <div {...n('tags').withTestId().props}>
            {ribbonBlock}
            {badgeBlockGrid}
        </div>
    );

    const ratingBlock = shouldRenderRating && (
        <div {...n('starsWrapper').withTestId().props}>
            <Rating
                rating={rating}
                numRatings={numRatings}
                caption={ratingCaption}
                title={i18n.rating}
            />
        </div>
    );

    const pricingCaption = !free ? i18n.from : null;
    const pricingFrequency = startingPrice && startingPrice.frequency && startingPrice.frequency.shortLabel
        ? startingPrice.frequency.label : null;
    const pricingBlock = startingPrice && (
        <div {...n('pricing').withTestId().props}>
            <Pricing
                isEmphasis={!isMobile && !showAsGrid}
                isMultipleLine={!showAsGrid && !isMobile}
                caption={pricingCaption}
                price={startingPrice.price}
                align={isMobile || showAsGrid ? null : 'right'}
                symbol={startingPrice.symbol}
                frequency={pricingFrequency}
            />
        </div>
    );

    const compareBlock = showCompareBtn && (
        <div {...n('compare', isDisabled && 'disabled').withTestId().props}>
            <Checkbox
                ariaLabel={`${i18n.selectToCompare}: ${name}`}
                label={i18n.compare}
                name={`compare-product-${id}`}
                isChecked={isCompareChecked}
                onChange={() => onCheckCompare && onCheckCompare(id)}
            />
        </div>
    );

    return (
        <article {...n('wrapper').withTestId().withE2EId().withVariables(componentVariables).props}>
            <a aria-label={name} href={url} {...n('overlayLink').props}>
                <span {...n('overlayLinkText').props}>{name}</span>
            </a>
            <div {...n('container', containerModifiers).withTestId().withE2EId().props}>
                {isLoading
                    ? getLoader()
                    : (
                        <React.Fragment>
                            <div {...n('header', headerBackgroundColor && 'with-bg-color').props}>
                                <div {...n('imageContainer', imageContainerModifiers).withTestId().props}>
                                    {imageBlock}
                                </div>
                                {showAsGrid && tagsBlock}
                                {!showAsGrid && ribbonBlock}
                            </div>
                            <div {...n('content').withTestId().props}>
                                <div {...n('information').props}>
                                    <div {...n('description').props}>
                                        <h2 {...n('title').withTestId().withE2EId('').props}>{name}</h2>
                                        {!showAsGrid && blurbBlock}
                                        {overviewBlock}
                                        {!showAsGrid && !isMobile && badgeBlock}
                                    </div>
                                    {(isMobile || showAsGrid) && merchandisingBadgesDisplay}
                                    {!hidePricings && pricingBlock}
                                </div>
                                <div {...n('footer').props}>
                                    {ratingBlock}
                                    {!showAsGrid && (
                                        <div {...n('footerCredit').props}>
                                            {versionBlock}
                                            {vendorNameBlock}
                                        </div>
                                    )}
                                    {compareBlock}
                                </div>
                            </div>
                        </React.Fragment>
                    )}
            </div>
        </article>
    );
};

const ICON_SIZE_OPTIONS = [SMALL, MEDIUM];

export const productListingCardForm = {
    iconSize: {
        title: 'uieditor.sfbComponent.productListCardForm.iconSize.title',
        type: DROPDOWN,
        required: true,
        defaultValue: ICON_SIZE_OPTIONS[0].value,
        options: ICON_SIZE_OPTIONS
    },
    titleColor: {
        title: 'uieditor.sfbComponent.productListCardForm.titleColor.title',
        type: COLORPICKER
    },
    headerBackgroundColor: {
        title: 'uieditor.sfbComponent.productListCardForm.headerBackgroundColor.title',
        type: COLORPICKER
    },
    backgroundColor: {
        title: 'uieditor.sfbComponent.productListCardForm.backgroundColor.title',
        type: COLORPICKER,
        defaultValue: '#ffffff'
    },
    borderColor: {
        title: 'uieditor.sfbComponent.productListCardForm.borderColor.title',
        type: COLORPICKER
    },
    borderRadius: {
        title: 'uieditor.sfbComponent.productListCardForm.borderRadius.title',
        type: SLIDER,
        defaultValue: 8,
        options: {
            range: true,
            min: 0,
            max: 35,
            step: 1
        }
    },
    isCompareVisible: {
        labelOn: 'uieditor.sfbComponent.productListCardForm.isCompareVisible.labelOn',
        labelOff: 'uieditor.sfbComponent.productListCardForm.isCompareVisible.labelOff',
        defaultValue: true,
        type: TOGGLE
    },
    isRatingsVisible: {
        labelOn: 'uieditor.sfbComponent.productListCardForm.isRatingsVisible.labelOn',
        labelOff: 'uieditor.sfbComponent.productListCardForm.isRatingsVisible.labelOff',
        defaultValue: true,
        type: TOGGLE
    },
    isVendorVisible: {
        labelOn: 'uieditor.sfbComponent.productListCardForm.isVendorVisible.labelOn',
        labelOff: 'uieditor.sfbComponent.productListCardForm.isVendorVisible.labelOff',
        defaultValue: true,
        type: TOGGLE
    },
    isBlurbVisible: {
        labelOn: 'uieditor.sfbComponent.productListCardForm.isBlurbVisible.labelOn',
        labelOff: 'uieditor.sfbComponent.productListCardForm.isBlurbVisible.labelOff',
        defaultValue: true,
        type: TOGGLE
    },
    isOverviewVisible: {
        labelOn: 'uieditor.sfbComponent.productListCardForm.isOverviewVisible.labelOn',
        labelOff: 'uieditor.sfbComponent.productListCardForm.isOverviewVisible.labelOff',
        defaultValue: true,
        type: TOGGLE
    }
};

ProductListingCard.schema = () => ({
    name: 'Product Listing Card',
    form: productListingCardForm
});

export const productListingSettingsShape = {
    iconSize: PropTypes.oneOf(ICON_SIZE_OPTIONS.map(({ value }) => value)),
    borderRadius: PropTypes.number,
    titleColor: PropTypes.string,
    headerBackgroundColor: PropTypes.string,
    backgroundColor: PropTypes.string,
    borderColor: PropTypes.string,
    isCompareVisible: PropTypes.bool,
    isRatingsVisible: PropTypes.bool,
    isVendorVisible: PropTypes.bool,
    isBlurbVisible: PropTypes.bool,
    isOverviewVisible: PropTypes.bool
};

ProductListingCard.propTypes = {
    data: PropTypes.shape(productListingCardShape),
    i18n: PropTypes.shape(i18nPropTypes),
    showAsGrid: PropTypes.bool,
    isCompareChecked: PropTypes.bool,
    isDisabled: PropTypes.bool,
    isLoading: PropTypes.bool,
    onCheckCompare: PropTypes.func,
    settings: PropTypes.shape(productListingSettingsShape)
};

const SETTINGS = ProductListingCard.schema().form;

ProductListingCard.defaultProps = {
    data: {
        hidePricings: false,
        iconUrl: PRODUCT_DEFAULT_IMG
    },
    i18n: {
        version: 'Version',
        soldBy: 'Sold by',
        compare: 'Compare',
        rating: 'Rating',
        selectToCompare: 'Select to compare',
        from: 'From',
        badges: 'Badges',
        merchandisingBadges: 'Merchandising Badges'
    },
    showAsGrid: false,
    isCompareChecked: false,
    isDisabled: false,
    isLoading: false,
    onCheckCompare: null,
    settings: {
        iconSize: SETTINGS.iconSize.defaultValue,
        borderRadius: SETTINGS.borderRadius.defaultValue,
        titleColor: SETTINGS.titleColor.defaultValue,
        headerBackgroundColor: SETTINGS.headerBackgroundColor.defaultValue,
        backgroundColor: SETTINGS.backgroundColor.defaultValue,
        borderColor: SETTINGS.borderColor.defaultValue,
        isCompareVisible: SETTINGS.isCompareVisible.defaultValue,
        isRatingsVisible: SETTINGS.isRatingsVisible.defaultValue,
        isVendorVisible: SETTINGS.isRatingsVisible.defaultValue,
        isBlurbVisible: SETTINGS.isBlurbVisible.defaultValue,
        isOverviewVisible: SETTINGS.isOverviewVisible.defaultValue
    }
};

export default ProductListingCard;
