import React from 'react';

import {Plus} from '@gravity-ui/icons';
import {Button, Card, Dialog, Icon, TextInput} from '@gravity-ui/uikit';
import block from 'bem-cn-lite';
import AutogeneratedPaletteIcon from 'components/AutogeneratedPaletteIcon/AutogeneratedPaletteIcon';
import {i18n} from 'i18n';
import type {ResolveThunks} from 'react-redux';
import {connect} from 'react-redux';
import type {ColorPalette} from 'shared';
import {
    deleteColorPalette,
    openDeletePaletteConfirm,
    saveCurrentPalette,
    setCurrentColorPalette,
} from 'store/actions/colorPaletteEditor';
import {selectColorPalettes, selectCurrentColorPalette} from 'store/selectors/colorPaletteEditor';
import type {DatalensGlobalState} from 'ui';
import {DialogRow} from 'units/wizard/components/Dialogs/components/DialogRow/DialogRow';
import {GradientPalettePreview} from 'units/wizard/components/GradientPalettePreview/GradientPalettePreview';
import {isStringWithFullLengthHex} from 'utils/validation';

import ColorPaletteChartkitPreview from '../ColorPaletteCharkitPreview/ColorPaletteChartkitPreview';
import ColorTextInput from '../ColorTextInput/ColorTextInput';

import './GradientPaletteEditor.scss';

const b = block('gradient-palette-editor');

type OwnProps = {
    hasEditRights?: boolean;
};

type StateProps = ReturnType<typeof mapStateToProps>;

type DispatchProps = ResolveThunks<typeof mapDispatchToProps>;

type GradientPaletteEditorProps = OwnProps & StateProps & DispatchProps;

class GradientPaletteEditor extends React.Component<GradientPaletteEditorProps> {
    render() {
        const {currentColorPalette, hasEditRights} = this.props;

        if (currentColorPalette?.isGradient !== true) {
            return null;
        }

        const textButtonApply = currentColorPalette.colorPaletteId
            ? i18n('component.color-palette-editor', 'button_apply')
            : i18n('component.color-palette-editor', 'button_save');

        const isApplyButtonDisabled = currentColorPalette.displayName.trim() === '';

        return (
            <Dialog open={true} size="l" onClose={this.handleCancelClick}>
                <Dialog.Header
                    caption={i18n('component.color-palette-editor', 'label_header-caption')}
                />
                <Dialog.Body className={b({'no-rights': !hasEditRights})}>
                    {this.renderDialogBody()}
                </Dialog.Body>
                {hasEditRights && (
                    <Dialog.Footer
                        onClickButtonCancel={this.handleCancelClick}
                        onClickButtonApply={this.handleApplyClick}
                        textButtonApply={textButtonApply}
                        propsButtonApply={{
                            disabled: isApplyButtonDisabled,
                        }}
                        textButtonCancel={i18n('component.color-palette-editor', 'button_cancel')}
                    >
                        {currentColorPalette.colorPaletteId ? (
                            <Button
                                view="outlined-danger"
                                size="l"
                                onClick={this.handleDeleteColorPalette}
                            >
                                {i18n('component.color-palette-editor', 'button_delete-title')}
                            </Button>
                        ) : null}
                    </Dialog.Footer>
                )}
            </Dialog>
        );
    }

    private handleDeleteColorPalette = () => {
        const {currentColorPalette} = this.props;

        if (currentColorPalette) {
            this.props.openDeletePaletteConfirm({
                onApply: () => {
                    this.props.deleteColorPalette(currentColorPalette);
                },
            });
        }
    };

    private renderDialogBody() {
        const {currentColorPalette, hasEditRights} = this.props;
        const cardMixinDark = 'chartkit-theme_common g-root_theme_dark';
        const cardMixinLight = 'chartkit-theme_common g-root_theme_light';

        if (!currentColorPalette) {
            return null;
        }

        return (
            <React.Fragment>
                <DialogRow
                    title={i18n('component.color-palette-editor', 'label_palette-name')}
                    setting={
                        <div className={b('name-setting')}>
                            <AutogeneratedPaletteIcon
                                className={b('palette-icon')}
                                isGradient={currentColorPalette.isGradient}
                                colors={currentColorPalette.colors}
                            />
                            {hasEditRights ? (
                                <TextInput
                                    className={b('name-input')}
                                    value={currentColorPalette.displayName}
                                    onUpdate={this.handleDisplayNameUpdate}
                                />
                            ) : (
                                <div className={b('name-input')}>
                                    {currentColorPalette.displayName}
                                </div>
                            )}
                        </div>
                    }
                />

                <div className={b('palette-charkit-preview')}>
                    <Card
                        className={b('palette-charkit-node', null, cardMixinDark)}
                        view="outlined"
                    >
                        <ColorPaletteChartkitPreview
                            colors={currentColorPalette.colors}
                            isGradient={currentColorPalette.isGradient}
                        />
                    </Card>
                    <Card
                        className={b('palette-charkit-node', null, cardMixinLight)}
                        view="outlined"
                    >
                        <ColorPaletteChartkitPreview
                            colors={currentColorPalette.colors}
                            isGradient={currentColorPalette.isGradient}
                        />
                    </Card>
                </div>

                <React.Fragment>
                    <GradientPalettePreview
                        className={b('palette-preview')}
                        colors={currentColorPalette.colors.filter(Boolean)}
                    />
                    {this.renderColorsInputs()}
                </React.Fragment>
            </React.Fragment>
        );
    }

    private renderColorsInputs() {
        const {currentColorPalette} = this.props;

        if (!currentColorPalette) {
            return null;
        }

        let left, middle, right;

        if (currentColorPalette.colors.length === 3) {
            [left, middle, right] = currentColorPalette.colors;
        } else {
            [left, right] = currentColorPalette.colors;
        }

        return (
            <div className={b('color-inputs')}>
                {this.renderColorTextInput({
                    currentColorPalette,
                    color: left,
                    index: 0,
                    showRemove: false,
                })}
                {this.renderColorTextInput({currentColorPalette, color: middle, index: 1})}
                {this.renderColorTextInput({
                    currentColorPalette,
                    color: right,
                    index: middle === undefined ? 1 : 2,
                    showRemove: false,
                })}
            </div>
        );
    }

    private renderColorTextInput(args: {
        currentColorPalette: ColorPalette;
        color: string | undefined;
        index: number;
        showRemove?: boolean;
    }) {
        const {currentColorPalette, color, index, showRemove} = args;
        const {hasEditRights} = this.props;

        if (color === undefined) {
            if (!hasEditRights) {
                return null;
            }

            return (
                <Button
                    key={index}
                    view="outlined"
                    onClick={() => {
                        const colors = [...currentColorPalette.colors];

                        colors.splice(1, 0, colors[0]);

                        this.props.setCurrentColorPalette({
                            ...currentColorPalette,
                            colors,
                        });
                    }}
                >
                    <Icon data={Plus} />
                </Button>
            );
        }

        return (
            <ColorTextInput
                value={color}
                error={!isStringWithFullLengthHex(color)}
                showRemove={showRemove}
                hasEditRights={hasEditRights}
                onUpdate={(value) => {
                    const colors = [...currentColorPalette.colors];

                    colors.splice(index, 1, value);

                    this.props.setCurrentColorPalette({
                        ...currentColorPalette,
                        colors,
                    });
                }}
                onRemove={
                    index === 1
                        ? () => {
                              const colors = currentColorPalette.colors.filter(
                                  (_, colorsIndex) => colorsIndex !== index,
                              );

                              this.props.setCurrentColorPalette({
                                  ...currentColorPalette,
                                  colors,
                              });
                          }
                        : undefined
                }
            />
        );
    }

    private handleDisplayNameUpdate = (displayName: string) => {
        const currentColorPalette = this.props.currentColorPalette!;

        this.props.setCurrentColorPalette({
            ...currentColorPalette,
            displayName,
        });
    };

    private handleApplyClick = () => {
        this.props.saveCurrentPalette();
    };

    private handleCancelClick = () => {
        this.props.setCurrentColorPalette(undefined);
    };
}

const mapStateToProps = (state: DatalensGlobalState) => {
    return {
        currentColorPalette: selectCurrentColorPalette(state),
        colorPalettes: selectColorPalettes(state),
    };
};

const mapDispatchToProps = {
    setCurrentColorPalette,
    saveCurrentPalette,
    openDeletePaletteConfirm,
    deleteColorPalette,
};

export default connect(mapStateToProps, mapDispatchToProps)(GradientPaletteEditor);
