import React, { useState } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import has from 'lodash/has';
import isArray from 'lodash/isArray';
import find from 'lodash/find';
import clsx from 'clsx';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import BlockRoundedIcon from '@material-ui/icons/BlockRounded';
import InfoRoundedIcon from '@material-ui/icons/InfoRounded';
import RestoreRoundedIcon from '@material-ui/icons/RestoreRounded';
import WarningRoundedIcon from '@material-ui/icons/WarningRounded';
import { withStyles } from '@material-ui/core/styles';
import Markdown from 'Framework/Components/Markdown';
import { t } from 'Framework/i18n';
import customClassName from 'App/Utils/customClassName';
import OptionAmount from '../OptionAmount';
import OptionGroup from '../OptionGroup';
import getImageUrl from '../../../../Utils/getImageUrl';
import AccessibleButton from '../../../../Shared/Components/AccessibleButton/AccessibleButton';

const styles = theme => {
    const textWidthWithAmount =
        theme.creator.option.image.width !== 'auto'
            ? `calc(94% - (${theme.creator.option.image.width} + 35px))`
            : theme.creator.option.textArea.textWidth;

    const customValues = {
        icon: {
            fontSize: '16px',
            lineHeight: 1.6,
        },
        image: {
            fontSize: '11px',
            lineHeight: '11px',
        },
        textArea: {
            fontSize: '0.8em',
            title: {
                fontWeight: 'bold',
            },
        },
    };

    return {
        description: {},
        materialIcon: {},
        price: {},
        details: {},
        iconWithText: {
            lineHeight: customValues.icon.lineHeight,
            display: 'inline-flex',
            verticalAlign: 'middle',
            '& $materialIcon': {
                float: 'left',
                display: 'inline-block',
                paddingRight: '8px',
                minWidth: '20px',
                textAlign: 'center',
            },
        },
        optionList: {
            overflow: 'hidden',
        },
        title: {
            fontWeight: 'bold',
            display: '-webkit-box',
            overflow: 'hidden',
            wordWrap: 'break-word',
            boxOrient: 'vertical',
            lineClamp: 3,
            textOverflow: 'ellipsis',
        },
        image: {
            display: 'inline-block',
            float: 'left',
            height: '100%',
            maxHeight: '100%',
            maxWidth: theme.creator.option.image.width,
            marginRight: '10px',
            fontSize: 0,

            '& img': {
                maxHeight: '100%',
                maxWidth: '100%',
            },
            '& .imageNotAvailableElement': {
                padding: '4px',
                lineHeight: customValues.image.lineHeight,
                fontSize: customValues.image.fontSize,
            },
        },
        root: {
            minHeight: '100px',
            padding: 10,
            cursor: 'pointer',
            fontSize: customValues.textArea.fontSize,
            display: 'flex',

            '& .content': {
                position: 'relative',
                display: 'flex',
                verticalAlign: 'middle',
                margin: 0,
                flex: 1,
            },
            '& .disabled': {
                cursor: 'not-allowed',
                opacity: '0.8',
            },
            '&.selected': {
                backgroundColor: '#d8d8d8',
            },
            tapHighlightColor: theme.tapHighlightColor,
        },
        text: {
            float: 'left',
            width: 'calc(94% - ' + theme.creator.option.image.width + ')',
            '& a': {
                textDecoration: 'underline',
            },
            '& $description': {
                marginBottom: 10,
                '& p': {
                    margin: 0,
                },
            },
            '& $price': {
                marginBottom: 10,
            },
            '& $title': {
                fontWeight: customValues.textArea.title.fontWeight,
                marginBottom: '10px',
            },
        },
        withAmount: {
            '& $text': {
                width: textWidthWithAmount,
            },
        },
        optionTextInput: {},
    };
};

const Option = ({ children, render, ...props }) => {
    const {
        className,
        onClick,
        onSelect,
        onToggle,
        onInputTextChange,
        option,
        optionclassification,
        selected,
        viewDetails,
        viewStockInformation,
        OptionAmountComponent,
        OptionGroupComponent,
        classes,
        isAdminMode,
    } = props;

    const [imageAvailable, setImageAvailable] = useState(true);
    const { selectedoptions } = optionclassification;
    const [inputText, setInputText] = useState(
        get(find(selectedoptions, ['identifier', option.identifier]), 'inputText', '')
    );
    const query = new URLSearchParams(location.search);
    const hidePrices = query.has('_hide_prices') && query.get('_hide_prices') === '1';
    const smallerScreen = useMediaQuery('(min-device-width : 300px) and (max-device-width : 340px)');
    const thumbnail = get(option, 'thumbnail', '');
    const detailImage = get(option, 'detailImage');
    const optionIdentifier = get(option, 'identifier', '');
    const amountIsSelectable = get(option, 'amount_is_selectable', false);
    const resultStatus = get(option, 'check_results.status', true);
    const optionIsMultiSelect = get(option, 'is_multiselect', false);
    const optionAmount = get(option, 'amount', 0);
    const hasTextinput = get(option, 'hasTextinput', false);
    const translations = {
        ...t('common'),
        ...t('optionlistitem'),
    };

    const setImageAvailability = () => {
        setImageAvailable(!imageAvailable);
    };

    const isEnabled = () => {
        return get(option, 'stock.traffic_light', false) !== 'red';
    };

    const shouldDisplayDetails = () => {
        return option.description || detailImage;
    };

    const onOptionSelected = () => {
        const optionClassificationIsMultiselect = get(optionclassification, 'is_multiselect', false);

        if (amountIsSelectable) {
            onSelect({
                ...option,
                amount: !optionAmount ? 1 : optionAmount,
            });
        } else if (optionClassificationIsMultiselect || isAdminMode) {
            onSelect({
                ...option,
                amount: selected ? 0 : 1,
            });
        } else if (!selected) {
            onSelect({
                ...option,
                amount: 1,
            });
        }
    };

    const onOptionClicked = event => {
        event.preventDefault();
        event.stopPropagation();

        if (isEnabled() && !(hasTextinput && selected)) {
            onOptionSelected();
            onClick();
        }
    };

    const onAmountChanged = optionAmount => {
        if (!isEnabled()) {
            return;
        }

        let amount;

        if (amountIsSelectable) {
            amount = optionAmount;
        } else if (optionIsMultiSelect) {
            amount = selected ? 0 : 1;
        } else if (!selected) {
            amount = 1;
        }

        if (amount < 0) {
            return; // prevent setting below 0
        }
        onSelect({
            ...option,
            amount,
        });
    };

    const onAbstractClicked = event => {
        event.target.tagName.toLowerCase() === 'a' && event.stopPropagation();
    };

    const onDetailsClicked = event => {
        event.stopPropagation();
        event.preventDefault();

        if (isEnabled()) {
            viewDetails(option);
        }
    };

    const onIncompatibilityClicked = event => {
        event.stopPropagation();
        event.preventDefault();

        if (isEnabled()) {
            onOptionSelected();
        }
    };

    const onOptionGroupClicked = event => {
        event.stopPropagation();
    };

    const onOptionGroupItemSelected = option => {
        onSelect({
            ...option,
            amount: 1,
        });
    };

    const onLateDeliveryClicked = event => {
        event.stopPropagation();
        event.preventDefault();

        if (isEnabled()) {
            viewStockInformation(option);
        }
    };

    const renderImage = () => {
        const src = getImageUrl(thumbnail);
        return (
            src && (
                <img
                    src={src}
                    alt={t('ariaLabels.optionImage', { title: option.title })}
                    onError={setImageAvailability}
                />
            )
        );
    };

    const renderNotAvailableImage = () => {
        return (
            <div className={'imageNotAvailableElement'}>
                <Typography variant={'caption'}>{translations.imageNotAvailable}</Typography>
            </div>
        );
    };

    const renderStockStatus = () => {
        if (option.stock) {
            switch (option.stock.traffic_light) {
                case 'red':
                    return (
                        <div className={classes.iconWithText}>
                            <BlockRoundedIcon className={classes.materialIcon} />{' '}
                            <Typography variant={'body2'}>{translations.notAvailable}</Typography>
                        </div>
                    );
                case 'yellow':
                    return (
                        <div>
                            <AccessibleButton
                                component="a"
                                className={classes.iconWithText}
                                onClick={onLateDeliveryClicked}
                            >
                                <RestoreRoundedIcon className={classes.materialIcon} />{' '}
                                <Typography variant={'body2'}>{translations.lateDelivery}</Typography>
                            </AccessibleButton>
                        </div>
                    );
                case 'green':
                    return null;
            }
        }
        return null;
    };

    const renderOptionGroup = () => {
        if (!isEnabled()) {
            return null;
        }

        const optionGroup = get(option, 'option_group', {});

        if (
            has(optionGroup, 'children') &&
            isArray(optionGroup.children) &&
            optionGroup.children.length > 0
        ) {
            return (
                <div onClick={onOptionGroupClicked}>
                    <OptionGroupComponent
                        itemGroup={optionGroup}
                        option={option}
                        optionclassification={optionclassification}
                        onOptionSelect={onOptionGroupItemSelected}
                        selected={selected}
                        onToggle={onToggle}
                    />
                </div>
            );
        }
        return null;
    };

    const renderActions = () => {
        let displayDetails = shouldDisplayDetails();

        return (
            <div className={classes.details}>
                {displayDetails && (
                    <div>
                        <AccessibleButton
                            component="a"
                            className={classes.iconWithText}
                            onClick={onDetailsClicked}
                        >
                            <InfoRoundedIcon
                                className={clsx(
                                    classes.materialIcon,
                                    customClassName('rule-info-icon-option')
                                )}
                            />
                            <Typography variant={'body2'} className={classes.iconWithText}>
                                {translations.details}
                            </Typography>
                        </AccessibleButton>
                    </div>
                )}

                {resultStatus !== true && (
                    <div>
                        <a className={classes.iconWithText} onClick={onIncompatibilityClicked}>
                            <WarningRoundedIcon
                                className={clsx(
                                    classes.materialIcon,
                                    customClassName('rule-alert-icon-option')
                                )}
                            />
                            <Typography variant={'body2'}>{translations.incompatibility}</Typography>
                        </a>
                    </div>
                )}

                {renderStockStatus()}

                {renderOptionGroup()}
            </div>
        );
    };

    const renderText = () => {
        return (
            <Grid item xs={12}>
                <Typography component={'div'} className={classes.optionList} variant={'body2'}>
                    <div className={classes.title}>{option.title}</div>
                    {hasTextinput && renderTextInput()}
                    {!hidePrices && <div className={classes.price}>{option.priceFormatted}</div>}
                    {smallerScreen && renderControls('horizontal')}
                    {option.abstract && (
                        <Markdown className={classes.description} onClick={onAbstractClicked}>
                            {option.abstract}
                        </Markdown>
                    )}

                    {renderActions()}
                </Typography>
            </Grid>
        );
    };

    const renderControls = view => {
        if (isEnabled() && amountIsSelectable && OptionAmountComponent) {
            return (
                <OptionAmountComponent
                    view={view}
                    option={option}
                    onAmountChange={onAmountChanged}
                    onSelect={onSelect}
                />
            );
        } else {
            return null;
        }
    };

    const handleTextInputChange = event => {
        setInputText(event.target.value);
        onInputTextChange(option.identifier, event.target.value);
    };

    const renderTextInput = () => {
        return (
            <TextField
                className={classes.optionTextInput}
                label={''}
                value={inputText}
                onChange={handleTextInputChange}
                disabled={!selected}
                translate="no"
            />
        );
    };

    const getRootClassName = () => clsx(classes.root, selected && 'selected', customClassName('option'));

    const getContentClassName = () => {
        const amountClass = amountIsSelectable && !smallerScreen ? classes.withAmount : '';
        return clsx(
            'content',
            className,
            optionIdentifier,
            amountClass,
            !isEnabled() && 'disabled',
            resultStatus !== true && 'incompatible'
        );
    };

    const getRenderProps = () => ({
        ...props,
        imageAvailable,
        smallerScreen,
        renderImage,
        renderNotAvailableImage,
        renderText,
        renderControls,
        renderActions,
        renderOptionGroup,
        renderStockStatus,
        setImageAvailability,
        isEnabled,
        shouldDisplayDetails,
        onOptionSelected,
        onOptionClicked,
        onAmountChanged,
        onAbstractClicked,
        onDetailsClicked,
        onIncompatibilityClicked,
        onOptionGroupClicked,
        onOptionGroupItemSelected,
        onLateDeliveryClicked,
        getRootClassName,
        getContentClassName,
    });

    const renderItem = () => {
        return (
            <AccessibleButton
                component="div"
                className={getRootClassName()}
                data-option={option.identifier}
                onClick={onOptionClicked}
                notAccessible={props.notAccessible}
            >
                <div className={getContentClassName()}>
                    {typeof children === 'function' ? (
                        children(getRenderProps())
                    ) : (
                        <>
                            <div className={classes.image}>
                                {imageAvailable ? renderImage() : renderNotAvailableImage()}
                            </div>

                            <div className={classes.text}>{renderText()}</div>

                            {!smallerScreen && renderControls()}
                        </>
                    )}
                </div>
            </AccessibleButton>
        );
    };

    return typeof render === 'function' ? render(getRenderProps()) : renderItem();
};

Option.defaultProps = {
    className: '',
    onClick: () => {},
    onSelect: () => {},
    onToggle: () => {},
    onInputTextChange: () => {},
    optionclassification: {},
    option: {},
    selected: false,
    translations: {},
    viewDetails: () => {},
    viewStockInformation: () => {},
    OptionAmountComponent: OptionAmount,
    OptionGroupComponent: OptionGroup,
    notAccessible: false,
};

Option.propTypes = {
    className: PropTypes.string,
    onClick: PropTypes.func,
    onSelect: PropTypes.func,
    onToggle: PropTypes.func,
    onInputTextChange: PropTypes.func,
    option: PropTypes.object,
    optionclassification: PropTypes.object,
    selected: PropTypes.bool,
    translations: PropTypes.object,
    viewDetails: PropTypes.func,
    viewStockInformation: PropTypes.func,
    OptionAmountComponent: PropTypes.elementType,
    OptionGroupComponent: PropTypes.elementType,
    isAdminMode: PropTypes.bool,
    children: PropTypes.func,
    render: PropTypes.func,
    notAccessible: PropTypes.bool,
};

export default withStyles(styles, { name: 'Option' })(Option);
