import React from 'react';

import {Button, Dialog} from '@gravity-ui/uikit';
import block from 'bem-cn-lite';
import {I18n} from 'i18n';
import {useSelector} from 'react-redux';
import type {DatasetField, DatasetFieldColorConfig, DatasetUpdate, FieldUISettings} from 'shared';
import {
    DatasetFieldColorsDialogQa,
    TIMEOUT_90_SEC,
    getFieldDistinctValues,
    getFieldsApiV2RequestSection,
    getParametersApiV2RequestSection,
} from 'shared';
import {ColorPaletteSelect} from 'ui/components/ColorPaletteSelect/ColorPaletteSelect';
import {ColorValueItem} from 'ui/components/ColorValueItem/ColorValueItem';
import {ValuesList} from 'ui/components/ValuesList/ValuesList';
import {PALETTE_DEFAULT_COLOR, getTenantDefaultColorPaletteId} from 'ui/constants';
import {getSdk} from 'ui/libs/schematic-sdk';
import {selectColorPalettesDict} from 'ui/store/selectors/colorPaletteEditor';
import {
    PaletteWithCustomColor,
    stripPaletteIndexColors,
} from 'ui/units/wizard/components/Dialogs/DialogColor/PaletteWithCustomColor/PaletteWithCustomColor';
import {getPaletteColors} from 'ui/utils';

import './ColorsDialog.scss';

// toDo: move to component keyset
const i18n = I18n.keyset('wizard');

const VALUES_LOAD_LIMIT = 1000;

const b = block('colors-dialog');

type Props = {
    open: boolean;
    field: DatasetField;
    fieldUiSettings: FieldUISettings;
    datasetId: string;
    updates?: DatasetUpdate[];
    workbookId?: string;
    parameters: DatasetField[];
    onClose: () => void;
    onApply: (args: DatasetFieldColorConfig) => void;
};

export const ColorsDialog = (props: Props) => {
    const {
        open,
        field,
        fieldUiSettings,
        datasetId,
        updates,
        workbookId,
        parameters,
        onClose,
        onApply,
    } = props;
    const [values, setValues] = React.useState<string[]>([]);
    const [selectedValue, setSelectedValue] = React.useState<string | undefined>();
    const [isLoading, setLoading] = React.useState(true);
    const [error, setError] = React.useState(null);

    const [mountedColors, setMountedColors] = React.useState<Record<string, string>>(
        fieldUiSettings?.colors ?? {},
    );

    const colorPalettes = useSelector(selectColorPalettesDict);

    const defaultPaletteId = getTenantDefaultColorPaletteId();
    const [selectedPaletteId, setSelectedPalette] = React.useState(
        fieldUiSettings?.palette ?? defaultPaletteId,
    );

    const colorsList: string[] = getPaletteColors(
        selectedPaletteId,
        Object.values(colorPalettes),
    ).concat([PALETTE_DEFAULT_COLOR]);

    React.useEffect(() => {
        setSelectedValue(values?.[0] ?? undefined);
    }, [values]);

    React.useEffect(() => {
        setMountedColors(fieldUiSettings?.colors ?? {});
        setSelectedPalette(fieldUiSettings?.palette ?? defaultPaletteId);
    }, [defaultPaletteId, fieldUiSettings?.colors, fieldUiSettings?.palette]);

    const loadValues = React.useCallback(async () => {
        getSdk().cancelRequest('getDistincts');

        try {
            const resp = await getSdk().sdk.bi.getDistinctsApiV2(
                {
                    datasetId,
                    updates,
                    workbookId: workbookId ?? null,
                    limit: VALUES_LOAD_LIMIT,
                    fields: getFieldsApiV2RequestSection([field], 'distinct'),
                    parameter_values: getParametersApiV2RequestSection({
                        parameters,
                        dashboardParameters: [],
                    }),
                },
                {concurrentId: 'getDistincts', timeout: TIMEOUT_90_SEC},
            );
            const distincts = getFieldDistinctValues(field, resp.result.data.Data);
            setValues(distincts);
        } catch (e) {
            setError(e);
        }
        setLoading(false);
    }, [datasetId, field, parameters, updates, workbookId]);

    React.useEffect(() => {
        loadValues();
    }, [loadValues]);

    const handleSelectColor = (color: string, colorIndex?: number) => {
        if (!selectedValue) {
            return;
        }

        const newMountedColors = {...mountedColors};

        if (colorIndex === undefined) {
            newMountedColors[selectedValue] = color;
            setMountedColors(newMountedColors);
            return;
        }

        const isDefaultColor =
            !colorsList[colorIndex] || colorsList[colorIndex] === PALETTE_DEFAULT_COLOR;

        if (mountedColors[selectedValue] && isDefaultColor) {
            delete newMountedColors[selectedValue];
        } else if (mountedColors[selectedValue] !== String(colorIndex) && !isDefaultColor) {
            newMountedColors[selectedValue] = String(colorIndex);
        }

        setMountedColors(newMountedColors);
    };

    const handleSelectPalette = (palettes: string[]) => {
        setSelectedPalette(palettes[0]);
        setMountedColors(stripPaletteIndexColors(mountedColors));
    };

    const handleApply = () => {
        onApply({colors: mountedColors, palette: selectedPaletteId});
    };

    const handleCancel = () => {
        onClose();
    };

    const handleReset = () => {
        setSelectedPalette(defaultPaletteId);
        setMountedColors({});
    };

    const renderValueItem = (value: string) => {
        return (
            <React.Fragment>
                <ColorValueItem
                    colorsList={colorsList}
                    color={mountedColors[value]}
                    qa={DatasetFieldColorsDialogQa.ValueItemColorIcon}
                />
                <div
                    data-qa={DatasetFieldColorsDialogQa.ValueItem}
                    className={b('value-label')}
                    title={value}
                >
                    {value}
                </div>
            </React.Fragment>
        );
    };

    const paletteSelectedValue = selectedValue ? mountedColors[selectedValue] : undefined;

    return (
        <Dialog
            qa={DatasetFieldColorsDialogQa.Dialog}
            onClose={onClose}
            open={open}
            className={b()}
            disableHeightTransition={true}
        >
            <Dialog.Header caption={i18n('label_colors-settings')} />
            <Dialog.Body className={b('body')}>
                <div className={b('content')}>
                    <ValuesList
                        values={values}
                        isLoading={isLoading}
                        error={error ? i18n('label_error-loading-filter-values') : undefined}
                        renderItem={renderValueItem}
                        className={b('values-list')}
                        selected={selectedValue}
                        onSelect={setSelectedValue}
                    />
                    <div className={b('palette-container')}>
                        <ColorPaletteSelect
                            colorPalettes={Object.values(colorPalettes)}
                            onUpdate={handleSelectPalette}
                            value={selectedPaletteId}
                        />
                        <PaletteWithCustomColor
                            className={b('palette')}
                            currentMountedColor={paletteSelectedValue}
                            selectedValue={selectedValue}
                            colorsList={colorsList}
                            onPaletteItemClick={handleSelectColor}
                            palleteItemQa={DatasetFieldColorsDialogQa.PaleteItem}
                        />
                    </div>
                </div>
            </Dialog.Body>
            <Dialog.Footer>
                <div className={b('footer')}>
                    <Button
                        size="l"
                        view="outlined"
                        className={b('btn-reset')}
                        onClick={handleReset}
                    >
                        {i18n('button_reset')}
                    </Button>
                    <Button size="l" view="flat" onClick={handleCancel}>
                        {i18n('button_cancel')}
                    </Button>
                    <Button size="l" view="action" onClick={handleApply}>
                        {i18n('button_apply')}
                    </Button>
                </div>
            </Dialog.Footer>
        </Dialog>
    );
};
