import React from 'react';

import {Plus} from '@gravity-ui/icons';
import type {ListSortParams} from '@gravity-ui/uikit';
import {Button, Card, Dialog, Icon, List, 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 {
    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 {isStringWithHex} from 'utils/validation';

import {PaletteEditorQA} from '../../../../shared';
import ColorPaletteChartkitPreview from '../ColorPaletteCharkitPreview/ColorPaletteChartkitPreview';
import ColorTextInput from '../ColorTextInput/ColorTextInput';

import './PaletteEditor.scss';

const MAX_COLORS_IN_PALETTE = 36;

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

type OwnProps = {
    hasEditRights?: boolean;
};

type StateProps = ReturnType<typeof mapStateToProps>;

type DispatchProps = ResolveThunks<typeof mapDispatchToProps>;

type PaletteEditorProps = OwnProps & StateProps & DispatchProps;

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

        if (currentColorPalette?.isGradient !== false) {
            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}
                onEscapeKeyDown={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,
                            qa: PaletteEditorQA.ApplyButton,
                        }}
                        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;

        if (!currentColorPalette) {
            return null;
        }

        const isAddColorButtonDisabled = currentColorPalette.colors.length >= MAX_COLORS_IN_PALETTE;

        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}
                                    qa={PaletteEditorQA.PaletteNameInput}
                                />
                            ) : (
                                <div className={b('name-input')}>
                                    {currentColorPalette.displayName}
                                </div>
                            )}
                        </div>
                    }
                />
                <div className={b('palette-editor')}>
                    <div className={b('palette-charkit-preview')}>
                        <Card
                            className={b(
                                'palette-charkit-node',
                                null,
                                'chartkit-theme_common g-root_theme_dark',
                            )}
                        >
                            <ColorPaletteChartkitPreview
                                colors={currentColorPalette.colors}
                                isGradient={currentColorPalette.isGradient}
                            />
                        </Card>
                        <Card
                            className={b(
                                'palette-charkit-node',
                                null,
                                'chartkit-theme_common g-root_theme_light',
                            )}
                        >
                            <ColorPaletteChartkitPreview
                                colors={currentColorPalette.colors}
                                isGradient={currentColorPalette.isGradient}
                            />
                        </Card>
                    </div>
                    <div className={b('palette-colors-list')}>
                        <List<string>
                            virtualized={false}
                            filterable={false}
                            sortable={Boolean(hasEditRights)}
                            renderItem={this.renderColorListItem}
                            items={currentColorPalette.colors}
                            itemClassName={b('list-item-wrapper')}
                            onSortEnd={this.handleSortEnd}
                        />
                        {hasEditRights && (
                            <div className={b('add-color-controls')}>
                                <Button
                                    className={b('add-color-button')}
                                    view="flat"
                                    onClick={this.handleAddColorClick}
                                    disabled={isAddColorButtonDisabled}
                                    qa={PaletteEditorQA.AddColorButton}
                                >
                                    <Icon data={Plus} />{' '}
                                    {i18n('component.color-palette-editor', 'label_add-color')}
                                </Button>
                                {isAddColorButtonDisabled ? (
                                    <span className={b('add-color-disabled-label')}>
                                        {i18n(
                                            'component.color-palette-editor',
                                            'label_add-color-disabled',
                                            {count: MAX_COLORS_IN_PALETTE},
                                        )}
                                    </span>
                                ) : null}
                            </div>
                        )}
                    </div>
                </div>
            </React.Fragment>
        );
    }

    private renderColorListItem = (color: string, _isItemActive: boolean, itemIndex: number) => {
        const showRemove = (this.props.currentColorPalette?.colors.length || 0) > 1;

        return (
            <ColorTextInput
                value={color}
                error={!isStringWithHex(color)}
                showRemove={showRemove}
                maxWidth={true}
                hasEditRights={this.props.hasEditRights}
                onUpdate={this.handleColorValueUpdate.bind(this, itemIndex)}
                onRemove={this.handleRemoveColorClick.bind(this, itemIndex)}
            />
        );
    };

    private handleAddColorClick = () => {
        const currentColorPalette = this.props.currentColorPalette!;

        this.props.setCurrentColorPalette({
            ...currentColorPalette,
            colors: currentColorPalette.colors.concat('#000'),
        });
    };

    private handleColorValueUpdate = (valueIndex: number, value: string) => {
        const currentColorPalette = this.props.currentColorPalette!;

        const colors = [...currentColorPalette.colors];

        colors.splice(valueIndex, 1, value);

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

    private handleRemoveColorClick = (valueIndex: number) => {
        const currentColorPalette = this.props.currentColorPalette!;

        const colors = [...currentColorPalette.colors];

        colors.splice(valueIndex, 1);

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

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

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

    private handleSortEnd = ({oldIndex, newIndex}: ListSortParams) => {
        const currentColorPalette = this.props.currentColorPalette!;

        const colors = [...currentColorPalette.colors];

        const swap = colors[newIndex];
        colors[newIndex] = colors[oldIndex];
        colors[oldIndex] = swap;

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

    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)(PaletteEditor);
