import React, { useState, forwardRef } from 'react';
import PropTypes from 'prop-types';
import './styles/ProductEditionCard.scss';
import { createNamespace } from '../../../tools/namingTools';
import { stripSlash } from '../../../tools/stringTools';
import { generateUniqueID } from '../../../tools/helpers';
import Badge from '../../badge/Badge';
import Bullet from '../../bullet/Bullet';
import Button from '../../button/Button';
import Icon from '../../icon/Icon';
import Pricing from '../../pricing/Pricing';
import { parsePricingAction } from '../../../tools/callToActions';

const n = createNamespace('ProductEditionCard');

const pickPriceElements = ({ unit, price, formattedFullPriceElements }) => ({
    unit,
    discount: {
        discountOff: price.formatted.discountOff
    },
    price: {
        original: price.formatted.originalFullPriceElements,
        formatted: formattedFullPriceElements
    }
});

const getPriceLimitLabel = priceUnit => {
    if (!priceUnit) {
        return null;
    }

    const hasOnlyMin = priceUnit.min === 1 && !priceUnit.max;
    const shouldRenderLimitLabel = priceUnit.limitLabel && !hasOnlyMin;

    return shouldRenderLimitLabel ? priceUnit.limitLabel.toLowerCase() : null;
};

const getActionLabel = (configuratorMode, isSelected, i18n, callToAction) => {
    if (configuratorMode) {
        return isSelected ? i18n.selected : i18n.select;
    }
    return callToAction ? callToAction.label : null;
};

const reducePrices = (flatPrice, unitPrice) => {
    const prices = [];

    // if there is a flat price, that needs to be shown first
    if (flatPrice) {
        prices.push(pickPriceElements(flatPrice));
    }

    // if there are unit prices, they need to be added
    if (unitPrice) {
        unitPrice.forEach(price => {
            price.usageRange.forEach(usageRange => {
                prices.push(pickPriceElements(usageRange));
            });
        });
    }

    return prices;
};

export const RenderPlan = ({ plan }) => (
    <div {...n('section').props} key={plan.uuid}>
        {Object.keys(plan.costs).length ? <RenderCosts plan={plan} /> : null}
    </div>
);

export const RenderCosts = ({ plan: {
    costs: { flatPrice, unitPrice },
    setupFees,
    contractFees,
    formattedContract,
    uuid
} }) => {
    // unify the prices into one array
    const prices = reducePrices(flatPrice, unitPrice);
    // split off the first element
    const [mainPrice, ...otherPrices] = prices;
    const shouldRenderPrices = !!otherPrices.length || !!setupFees.length || !!contractFees.length;

    return (
        <React.Fragment>
            {mainPrice && (
                <div {...n('mainPrice').props}>
                    <RenderPrice unit={mainPrice.unit} formattedPrice={mainPrice.price.formatted} />
                    {formattedContract && <Badge label={formattedContract} {...n('contract').props} />}
                    <RenderDiscount
                        discountOff={mainPrice.discount.discountOff}
                        original={mainPrice.price.original}
                    />
                </div>
            )}
            {shouldRenderPrices && (
                <div {...n('otherPrice').props}>
                    {otherPrices && !!otherPrices.length && otherPrices.map(otherPrice => (
                        <RenderPrice
                            unit={otherPrice.unit}
                            formattedPrice={otherPrice.price.formatted}
                            key={generateUniqueID([...otherPrice.price.formatted, uuid])}
                            isSecondary
                        />
                    ))}
                    {setupFees && !!setupFees.length && setupFees.map(setupFee => (
                        <RenderPrice
                            formattedPrice={setupFee.formattedFullPriceElements}
                            key={generateUniqueID([...setupFee.formattedFullPriceElements, uuid])}
                            isSecondary
                            textSeparator={' '}
                        />
                    ))}
                    {contractFees && !!contractFees.length && contractFees.map(contractFee => (
                        <RenderPrice
                            formattedPrice={contractFee.formattedFullPriceElements}
                            key={generateUniqueID([...contractFee.formattedFullPriceElements, uuid])}
                            isSecondary
                            textSeparator={' '}
                        />
                    ))}
                </div>
            )}
        </React.Fragment>
    );
};

export const RenderPrice = ({
    formattedPrice: [price, priceUnit, frequency],
    isSecondary,
    textSeparator,
    unit
}) => (
    <div {...n('pricing', !isSecondary && 'primary').withTestId().withE2EId().props}>
        <Pricing
            price={price}
            prefixIcon={isSecondary ? 'plus' : ''}
            frequency={frequency ? stripSlash(frequency.toLowerCase()) : ''}
            unit={priceUnit ? stripSlash(priceUnit.toLowerCase()) : ''}
            isEmphasis={!isSecondary}
            textSeparator={textSeparator}
            limitLabel={getPriceLimitLabel(unit)}
        />
    </div>
);

export const RenderDiscount = ({
    original: [originalPrice],
    discountOff
}) => {
    if (!discountOff) {
        return null;
    }
    return (
        <div {...n('discountSection').props}>
            <span {...n('discountLabel').props}>{originalPrice}</span>
            {discountOff && (<span {...n('discountOff').props}>{`(${discountOff})`}</span>)}
        </div>
    );
};

export const RenderButton = ({ configuratorMode, isSelected, i18n, id, callToAction, onSelect }) => {
    const label = getActionLabel(configuratorMode, isSelected, i18n, callToAction);
    const buttonExtraClass = callToAction.actionType && `btn-edition-${callToAction.actionType.toLowerCase()}`;

    return label ? (
        <div {...n('buttonWrapper').withTestId('actions-container').withE2EId('actions-container').props}>
            <Button
                data-testid={`button:select:edition-${id}`}
                type={isSelected ? 'emphasis-outline' : 'primary'}
                selected={isSelected}
                onClick={onSelect}
                extraClass={buttonExtraClass}
                wide
            >
                {isSelected ? <Icon type="check" {...n('selectedCheck').props} /> : null}
                {label}
            </Button>
        </div>
    ) : '';
};

export const RenderInclusions = ({ items, i18n }) => {
    if (!items || !items.length) {
        return null;
    }

    return (
        <div {...n('inclusions').props}>
            <span {...n('sectionTitle').withTestId('inclusionsTitle').withE2EId('inclusionsTitle').props}>{i18n.inclusions}</span>
            {items.map(({ content }) => (
                <div key={`includes-${content}`} {...n().withTestId('inclusionsItem').withE2EId('inclusionsItem').props}>
                    {content}
                </div>
            ))}
        </div>
    );
};

export const RenderAudience = ({ audience, i18n }) => {
    if (!audience || !audience.length) {
        return null;
    }

    return (
        <div {...n('audience').props}>
            <span {...n('sectionTitle').withTestId('audienceTitle').withE2EId('audienceTitle').props}>{i18n.audience}</span>
            {audience.map(({ content }) => (
                <div key={`audience-${content}`} {...n('section').withTestId('audienceItem').withE2EId('audienceItem').props}>
                    {content}
                </div>
            ))}
        </div>
    );
};

export const RenderBullet = ({ bullet }) => {
    const { content, tooltip } = bullet;
    return (
        <li {...n('bullet').withTestId().withE2EId('bullet').props}>
            <Bullet content={content} tooltip={tooltip} iconType="check" />
        </li>
    );
};

export const RenderBullets = ({ bullets }) => {
    if (!bullets || !bullets.length) {
        return null;
    }
    return (
        <ul {...n('bullets').props}>
            {bullets.map((bullet, index) => (
                <RenderBullet bullet={bullet} key={generateUniqueID([bullet.content, index])} />
            ))}
        </ul>
    );
};

export const ProductEditionCardComponent = forwardRef((
    {
        data: {
            id,
            name,
            description,
            primary,
            plans,
            audience,
            items,
            bullets,
            callToAction,
            freeTrialDuration,
            freeTrialType
        },
        configuratorMode,
        isDetailCollapsed,
        isSelected,
        onSelect,
        onExpand,
        titleHeight,
        height,
        i18n
    },
    forwardedRefs
) => {
    const [isCollapse, setCollapseState] = useState(true);
    const pricingAction = parsePricingAction(callToAction);

    const {
        titleRef,
        mainRef
    } = forwardedRefs || {};

    if (isDetailCollapsed !== null && isDetailCollapsed !== isCollapse) {
        setCollapseState(isDetailCollapsed);
    }

    const toggleDetails = () => {
        if (onExpand) {
            onExpand();
        } else {
            setCollapseState(!isCollapse);
        }
    };

    const containerModifiers = [
        primary && 'with-ribbon'
    ];
    const containerVariables = {
        infoHeight: (height && `${height}px`) || 'auto',
        titleHeight: (titleHeight && `${titleHeight}px`) || 'auto'
    };

    const mainModifiers = [
        configuratorMode && 'configurator-mode',
        primary && 'with-ribbon',
        configuratorMode && 'with-buttons',
        !isCollapse && 'with-details'
    ];

    // Remove empty costs from the plans array
    const productPlans = plans && plans.length ? plans.reduce((previous, current) => {
        if (current.costs && Object.keys(current.costs).length !== 0) {
            previous.push(current);
        }

        return previous;
    }, []) : null;

    return (
        <div {...n('container', containerModifiers).withVariables(containerVariables).withTestId().withE2EId().props}>
            <div {...n('main', mainModifiers).props} ref={mainRef}>
                {primary && <div {...n('ribbon').withTestId().withE2EId().props}>{i18n.mostPopular}</div>}
                <div {...n('header').props} ref={titleRef}>
                    <h2 {...n('title').withTestId().withE2EId().props}>{name}</h2>
                    {description && <p {...n('description').withTestId().withE2EId().props}>{description}</p>}
                    {freeTrialDuration && freeTrialType && (
                        <div {...n('trialContainer').props}>
                            <Badge {...n('trialBadge').props} label={`${freeTrialDuration} ${freeTrialType} ${i18n.freeTrial}`} type="success" />
                        </div>
                    )}
                </div>
                {productPlans && productPlans.length ? (
                    <div {...n('plans').props}>
                        {plans.map(plan => <RenderPlan plan={plan} key={plan.uuid} />)}
                    </div>
                ) : ''}
                <div {...n('actionsWrapper').props}>
                    <RenderButton
                        configuratorMode={configuratorMode}
                        isSelected={isSelected}
                        onSelect={onSelect}
                        i18n={i18n}
                        id={id}
                        callToAction={pricingAction}
                    />
                    {configuratorMode && (
                        <div {...n('actionLink').withE2EId().props}>
                            <Button
                                buttonType="link"
                                type="primary"
                                onClick={toggleDetails}
                                onKeyDown={toggleDetails}
                                extraClass="btn-toggle-details"
                                {...n('actionLinkLabel').withTestId().props}
                            >
                                {isCollapse ? i18n.viewDetails : i18n.hideDetails}
                            </Button>
                        </div>
                    )}
                </div>
            </div>
            {!isCollapse && (
                <div {...n('details').withTestId().withE2EId().props}>
                    {items && <RenderInclusions items={items} i18n={i18n} />}
                    {audience && <RenderAudience audience={audience} i18n={i18n} />}
                    {bullets && <RenderBullets bullets={bullets} />}
                </div>
            )}
        </div>
    );
});


const i18nDefault = {
    audience: 'Ideal For',
    inclusions: 'Included',
    mostPopular: 'Most Popular',
    select: 'Select',
    selected: 'Selected',
    hideDetails: 'Hide Details',
    viewDetails: 'View Details',
    freeTrial: 'free trial'
};

const planDefault = {
    costs: {},
    setupFees: [],
    constractFees: [],
    formattedContract: '',
    uuid: ''
};

const bulletSchema = PropTypes.shape({
    content: PropTypes.string,
    tooltip: PropTypes.string
});

const bulletsSchema = PropTypes.arrayOf(bulletSchema);

const i18nSchema = PropTypes.shape({
    audience: PropTypes.string,
    inclusions: PropTypes.string,
    mostPopular: PropTypes.string,
    select: PropTypes.string,
    selected: PropTypes.string,
    hideDetails: PropTypes.string,
    viewDetails: PropTypes.string,
    freeTrial: PropTypes.string
});

const callToActionSchema = PropTypes.shape({
    label: PropTypes.string,
    tooltip: PropTypes.string,
    isPrimary: PropTypes.bool,
    enabled: PropTypes.bool,
    url: PropTypes.string,
    actionType: PropTypes.string,
    popup: PropTypes.shape(),
    isSecondary: PropTypes.bool
});

const priceTypeSchema = PropTypes.shape({
    formattedFullPriceElements: PropTypes.arrayOf(PropTypes.string),
    originalFullPriceElements: PropTypes.arrayOf(PropTypes.string),
    unit: PropTypes.shape({
        limitLabel: PropTypes.string
    })
});

const planSchema = PropTypes.shape({
    costs: PropTypes.shape({
        flatPrice: priceTypeSchema,
        unitPrice: PropTypes.arrayOf(priceTypeSchema)
    }),
    setupFees: PropTypes.arrayOf(
        PropTypes.shape({
            formattedFullPriceElements: PropTypes.arrayOf(PropTypes.string)
        })
    ),
    contractFees: PropTypes.arrayOf(
        PropTypes.shape({
            formattedFullPriceElements: PropTypes.arrayOf(PropTypes.string)
        })
    ),
    formattedContract: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
    uuid: PropTypes.string
});

const plansSchema = PropTypes.arrayOf(planSchema);

const itemsSchema = PropTypes.arrayOf(
    PropTypes.shape({
        content: PropTypes.string
    })
);

const dataAudienceSchema = PropTypes.arrayOf(
    PropTypes.shape({
        content: PropTypes.string
    })
);

RenderBullets.propTypes = {
    bullets: bulletsSchema
};

RenderBullets.defaultProps = {
    bullets: []
};

RenderBullet.propTypes = {
    bullet: bulletSchema
};

RenderBullet.defaultProps = {
    bullet: {}
};

RenderAudience.propTypes = {
    audience: dataAudienceSchema,
    i18n: i18nSchema
};

RenderAudience.defaultProps = {
    audience: [],
    i18n: i18nDefault
};

RenderInclusions.propTypes = {
    items: itemsSchema,
    i18n: i18nSchema
};

RenderInclusions.defaultProps = {
    items: [],
    i18n: i18nDefault
};

RenderButton.propTypes = {
    configuratorMode: PropTypes.bool,
    isSelected: PropTypes.bool,
    onSelect: PropTypes.func,
    i18n: i18nSchema,
    id: PropTypes.number,
    callToAction: callToActionSchema
};

RenderButton.defaultProps = {
    configuratorMode: false,
    isSelected: false,
    onSelect: () => {},
    i18n: i18nDefault,
    id: 0,
    callToAction: {}
};

RenderDiscount.propTypes = {
    discountOff: PropTypes.string,
    original: PropTypes.arrayOf(PropTypes.string)
};

RenderDiscount.defaultProps = {
    discountOff: '',
    original: null
};

RenderPrice.propTypes = {
    formattedPrice: PropTypes.arrayOf(PropTypes.string),
    isSecondary: PropTypes.bool,
    textSeparator: PropTypes.string,
    unit: PropTypes.shape({
        min: PropTypes.number,
        max: PropTypes.number,
        limitLabel: PropTypes.string
    })
};

RenderPrice.defaultProps = {
    formattedPrice: [],
    isSecondary: false,
    textSeparator: '/',
    unit: null
};

RenderPlan.propTypes = {
    plan: planSchema
};

RenderPlan.defaultProps = {
    plan: PropTypes.shape(planDefault)
};

RenderCosts.propTypes = {
    plan: planSchema
};

RenderCosts.defaultProps = {
    plan: PropTypes.shape(planDefault)
};

export const defaultEditionsProps = PropTypes.shape({
    id: PropTypes.number,
    name: PropTypes.string,
    description: PropTypes.string,
    primary: PropTypes.bool,
    plans: plansSchema,
    audience: dataAudienceSchema,
    items: itemsSchema,
    bullets: PropTypes.arrayOf(
        PropTypes.shape({
            content: PropTypes.string,
            tooltip: PropTypes.string
        })
    ),
    callToAction: callToActionSchema,
    freeTrialDuration: PropTypes.number,
    freeTrialType: PropTypes.string
});

ProductEditionCardComponent.schema = () => ({
    name: 'Product Editions',
    form: {}
});

ProductEditionCardComponent.propTypes = {
    data: defaultEditionsProps,
    i18n: i18nSchema,
    titleHeight: PropTypes.number,
    height: PropTypes.number,
    isSelected: PropTypes.bool,
    configuratorMode: PropTypes.bool,
    isDetailCollapsed: PropTypes.bool,
    onSelect: PropTypes.func,
    onExpand: PropTypes.func
};

ProductEditionCardComponent.defaultProps = {
    data: {},
    i18n: i18nDefault,
    titleHeight: null,
    height: null,
    isSelected: false,
    configuratorMode: false,
    isDetailCollapsed: null,
    onSelect: () => {},
    onExpand: null
};

export default ProductEditionCardComponent;
