import type {ChartData, ChartSeries, ChartSeriesData} from '@gravity-ui/chartkit/gravity-charts';
import {CustomShapeRenderer} from '@gravity-ui/chartkit/gravity-charts';
import get from 'lodash/get';
import merge from 'lodash/merge';
import set from 'lodash/set';
import type {ExtendedChartData} from 'shared/types/chartkit';
import type {ChartKitHolidays} from 'ui/store/toolkit/chartkit/types';

import type {GraphWidget} from '../../../types';
import type {ChartKitAdapterProps} from '../../types';
import {getTooltipHeaderFormat, getTooltipRenderer, getTooltipRowRenderer} from '../tooltip';
import {getEscapedActionParams, getIsHolidaysEnabled, getNormalizedClickActions} from '../utils';

import {convertChartCommentsToPlotBandsAndLines, shouldUseCommentsOnYAxis} from './comments';
import {handleClick} from './event-handlers';
import {convertHolidaysToPlotBands} from './holidays';
import {
    getCustomShapeRenderer,
    isPointSelected,
    setPointSelectState,
    setSeriesSelectState,
} from './utils';

const SERIES_TYPES_WITH_CROSSHAIR: ChartSeries['type'][] = ['area', 'bar-x', 'line'];
const CROSSHAIR_COLOR = '#a63eb2';

export function getGravityChartsChartKitData(args: {
    loadedData: ChartKitAdapterProps['loadedData'];
    chartkitHolidays?: ChartKitHolidays;
    onChange?: ChartKitAdapterProps['onChange'];
    runActivity?: ChartKitAdapterProps['runActivity'];
    splitTooltip?: boolean;
    lang?: string;
}) {
    const {loadedData, chartkitHolidays, runActivity, onChange, splitTooltip, lang} = args;
    const widgetData = loadedData?.data as ExtendedChartData;
    const chartId = loadedData?.entryId;

    const chartWidgetData: Partial<ChartData> = {
        chart: {
            events: {
                click: (data, event) => {
                    handleClick({
                        widgetData: loadedData as GraphWidget,
                        point: data.point,
                        series: widgetData.series.data.find(
                            (s) => get(s, 'name') === get(data.series, 'name'),
                        ),
                        event,
                        onChange,
                        runActivity,
                    });
                },
            },
        },
        legend: {
            justifyContent: 'start',
            itemDistance: 24,
            itemStyle: {
                fontSize: '13px',
            },
        },
        tooltip: {
            pin: {enabled: true, modifierKey: 'altKey'},
            sorting: {key: 'value', direction: 'desc'},
            dateTimeLabelFormats: {
                day: `D MMMM YYYY ${lang === 'en' ? 'ddd' : 'dd'}`,
                week: 'D MMMM YYYY',
                month: 'MMMM YYYY',
            },
        },
        series: getStyledSeries(loadedData),
    };

    const result = merge({}, chartWidgetData, widgetData);

    if (result.title) {
        result.title.qa = 'g-charts-title';
    }

    if (!result.tooltip) {
        result.tooltip = {};
    }

    const tooltipQa = `chartkit-tooltip-entry-${chartId}`;
    result.tooltip.qa = tooltipQa;

    const rowRenderer = getTooltipRowRenderer({widgetData});
    result.tooltip.renderer = getTooltipRenderer({
        rowRenderer,
        qa: tooltipQa,
        totals: result.tooltip?.totals,
        valueFormat: result.tooltip?.valueFormat,
        widgetData,
    });
    result.tooltip.rowRenderer = rowRenderer;
    result.tooltip.headerFormat = getTooltipHeaderFormat({
        widgetData,
    });

    result.series?.data.forEach((s) => {
        set(s, 'legend.symbol', {
            padding: 7,
            width: 10,
            height: 10,
            ...s.legend?.symbol,
        });

        s.dataLabels = {
            padding: 10,
            ...s.dataLabels,
            style: {
                fontSize: '12px',
                fontWeight: '500',
                ...s.dataLabels?.style,
            },
        };

        switch (s.type) {
            case 'pie': {
                const totals = get(s, 'custom.totals');
                const renderCustomShapeFn = get(s, 'renderCustomShape') as any;

                if (renderCustomShapeFn) {
                    s.renderCustomShape = getCustomShapeRenderer(renderCustomShapeFn);
                } else if (typeof totals !== 'undefined') {
                    s.renderCustomShape = CustomShapeRenderer.pieCenterText(totals, {
                        padding: '25%',
                        minFontSize: 6,
                    });
                }

                break;
            }
        }
    });

    const hideComments = get(loadedData, 'config.hideComments', false);
    const comments = hideComments ? [] : get(loadedData, 'comments', []);
    const {plotBands, plotLines} = convertChartCommentsToPlotBandsAndLines({comments});

    const isHolidaysEnabled = getIsHolidaysEnabled({widgetData: loadedData});
    const holidaysPlotBands = isHolidaysEnabled
        ? convertHolidaysToPlotBands({holidays: chartkitHolidays, loadedData})
        : [];

    if (shouldUseCommentsOnYAxis(result)) {
        set(result, 'yAxis[0].plotBands', [...(result.yAxis?.[0]?.plotBands ?? []), ...plotBands]);
        set(result, 'yAxis[0].plotLines', [...(result.yAxis?.[0]?.plotLines ?? []), ...plotLines]);
    } else {
        set(result, 'xAxis.plotBands', [
            ...(result.xAxis?.plotBands ?? []),
            ...holidaysPlotBands,
            ...plotBands,
        ]);
        set(result, 'xAxis.plotLines', [...(result.xAxis?.plotLines ?? []), ...plotLines]);
    }

    if (splitTooltip) {
        set(result, 'chart.zoom.enabled', false);
        set(result, 'legend.enabled', false);
        set(result, 'series.options.area.states.hover.marker.enabled', false);
        set(result, 'series.options.line.states.hover.marker.enabled', false);

        const hasSeriesWithCrosshair = result.series?.data.some((s) =>
            SERIES_TYPES_WITH_CROSSHAIR.includes(s.type),
        );

        if (hasSeriesWithCrosshair) {
            set(result, 'xAxis.crosshair', {enabled: true, color: CROSSHAIR_COLOR});
        }
    }

    return result;
}

function getStyledSeries(loadedData: ChartKitAdapterProps['loadedData']) {
    const widgetData = loadedData?.data as ChartData;
    const clickActions = getNormalizedClickActions(loadedData as GraphWidget);
    const clickScope = clickActions.find((a) => {
        const handlers = Array.isArray(a.handler) ? a.handler : [a.handler];
        return handlers.some((h) => h.type === 'setActionParams');
    });
    const actionParams = getEscapedActionParams(loadedData);

    if (clickScope?.scope === 'point' && Object.keys(actionParams).length > 0) {
        const chartSeries = widgetData.series.data;
        const hasSomePointSelected = chartSeries.some((s) =>
            s.data.some((p) => isPointSelected(p, s, actionParams)),
        );

        if (hasSomePointSelected) {
            chartSeries.forEach((s) => {
                const points = s.data as ChartSeriesData[];
                const hasAnySelectedPoints = points.reduce((acc, p: ChartSeriesData) => {
                    const pointSelected = isPointSelected(p, s, actionParams);
                    setPointSelectState({point: p, series: s, selected: pointSelected});
                    return acc || pointSelected;
                }, false);
                setSeriesSelectState({series: s, selected: hasAnySelectedPoints});
            });
        }
    }

    return widgetData.series;
}
