import React, {memo, useEffect, useMemo, useRef} from 'react';
import {BasicChart} from '@wisdom-components/basicchart';
import optionGenerator, {
    alarmMarkLine,
    specialTypeChartOptionGenerator,
} from './utils';
import {isArray, cloneDeep} from 'lodash';
import moment from "moment";
import patchBIOption from "./useBIMode";
import {BI, Normal} from './theme';
import * as echarts from 'echarts';

echarts.registerTheme('BI', BI)
echarts.registerTheme('Normal', Normal)

const SingleChart = memo((props) => {
    const {
        dataSource,
        contrast = false,
        contrastOption = 'day',
        smooth = true,
        curveCenter,
        showGridLine = true,
        deviceAlarmSchemes,
        chartType,
        lineDataType,
        showBoxOption,
        special,
        predicateData,
        emptyOrError,
        theme = "Normal",
        exportCanvas
    } = props;
    const chartRef = useRef();
    const timerRef = useRef();
    const SpecialType = ['状态值', '开关值']; // 横向柱状条

    const minMaxMarkPoint = (dataSource,chart) => {
        // 只有一个数据曲线时显示markline
        if (dataSource.length !== 1) return {};
        // 1. 找出最大、最小的值
        let pointArr = dataSource[0].dataModel;
        let valueArr = pointArr.map(item => item.pv);
        let maxValue = Math.max(...valueArr);
        let minValue = Math.min(...valueArr);
        // 2. 找出点的索引和实际的点
        let maxValueIndex = valueArr.findIndex(val => val === maxValue);
        let minValueIndex = valueArr.findIndex(val => val === minValue);
        let maxPoint = pointArr[maxValueIndex];
        let minPoint = pointArr[minValueIndex];
        if (!maxPoint || !minPoint) return {}
        // 3. 计算坐标位置，返回的是 [x,y]的像素坐标
        let maxPointPosition = chart.convertToPixel({seriesIndex: 0}, [moment(maxPoint.pt).valueOf(), maxPoint.pv])
        let minPointPosition = chart.convertToPixel({seriesIndex: 0}, [moment(minPoint.pt).valueOf(), minPoint.pv])
        if (!maxPointPosition || !minPointPosition) return;
        // 4. 计算最大最小值的标签宽度
        let maxLength = 80 + String(maxValue).length * 5;
        let minLength = 80 + String(minValue).length * 5;
        // 5. 获取实例的宽度
        let chartWidth = chart.getWidth();
        // 6. 确定是否超出边界，确定超出边界是哪一边；
        let maxTagLeft = maxPointPosition[0] - maxLength / 2;
        let maxTagRight = maxPointPosition[0] + maxLength / 2;
        let minTagLeft = minPointPosition[0] - minLength / 2;
        let minTagRight = minPointPosition[0] + minLength / 2;
        let maxOutEdge = false, minOutEdge = false;
        let maxOutSide = '', minOutSide = '';

        // 在实际使用中，我们认为不存在一个tag同时超出边界的情况。
        if (maxTagLeft < 0) {
            maxOutEdge = true;
            maxOutSide = 'left';
        }
        if (maxTagRight > chartWidth) {
            maxOutEdge = true;
            maxOutSide = 'right';
        }

        if (minTagLeft < 0) {
            minOutEdge = true;
            minOutSide = 'left';
        }
        if (minTagRight > chartWidth) {
            minOutEdge = true;
            minOutSide = 'right';
        }
        // 7. 确定使用的图形
        // 默认图形，居中
        let maxIconPath = `path://M1233.329493 195.75466633h-1112.064c-34.128213 0-61.781333 27.661653-61.781333 61.781334v473.658026c0 34.117973 27.65312 61.781333 61.781333 61.781334h472.80128l83.23072 144.155306 83.23072-144.155306h472.80128c34.128213 0 61.781333-27.66336 61.781334-61.781334V257.53600033c0-34.117973-27.65312-61.781333-61.781334-61.781334z`;
        let maxSymbolOffset = [0, -20];
        if (maxOutEdge) {
            if (maxOutSide === 'left') {
                // 左边界超出，使用朝右的图表
                maxSymbolOffset = ['50%', -20];
                maxIconPath = 'path://M48.677,6.151v10c0,1.7-1.3,3-3,3h-35.5l-6.7,4c0,0,0.2-5.3,0.2-7v-10c0-1.7,1.3-3,3-3h39C47.277,3.151,48.677,4.551,48.677,6.151z';
            } else if (maxOutSide === 'right') {
                // 右边界超出，使用朝左的图表
                maxSymbolOffset = ['-50%', -20];
                maxIconPath = 'path://M6.477,3.151h39c1.7,0,3,1.3,3,3v10c0,1.7,0.2,7,0.2,7l-6.7-4h-35.5c-1.7,0-3-1.3-3-3v-10C3.477,4.551,4.877,3.151,6.477,3.151z'
            }
        }
        // 默认图形
        let minIconPath = 'path://M131.999 849.579h1112.064c34.128 0 61.781-27.662 61.781-61.781v-473.658c0-34.118-27.653-61.781-61.781-61.781h-472.801l-83.231-144.155-83.231 144.155h-472.801c-34.128 0-61.781 27.663-61.781 61.781v473.658c0 34.118 27.653 61.781 61.781 61.781z';
        let minSymbolOffset = [0, 20];
        if (minOutEdge) {
            if (minOutSide === 'left') {
                // 左边界超出，使用朝右的图表
                minSymbolOffset = ['50%', 20];
                minIconPath = 'path://M45.677,23.151h-39c-1.7,0-3-1.3-3-3v-10c0-1.7-0.2-7-0.2-7l6.7,4h35.5c1.7,0,3,1.3,3,3v10C48.677,21.751,47.277,23.151,45.677,23.151z';
            } else if (minOutSide === 'right') {
                // 右边界超出，使用朝左的图表
                minSymbolOffset = ['-50%', 20];
                minIconPath = 'path://M3.477,20.151v-10c0-1.7,1.3-3,3-3h35.5l6.7-4c0,0-0.2,5.3-0.2,7v10c0,1.7-1.3,3-3,3h-39C4.877,23.151,3.477,21.751,3.477,20.151z'
            }
        }

        const data = [
            {
                type: 'min',
                color: 'rgba(255,255,255,1)',
                name: '最小: ',
                symbolOffset: minSymbolOffset,
                symbol: minIconPath,
                symbolSize: (e) => {
                    let str = ![undefined, null].includes(e) ? String(e) : '';
                    let length = 60 + str.length * 6
                    return [length, 32]
                },
                label: {
                    show: true,
                    color: '#fff',
                    formatter: '最小: {c}',
                    fontSize: 14,
                    fontWeight: 'bold',
                    verticalAlign: 'top',
                    offset: [0, -2]
                },
                itemStyle: {
                    // color: "#21c8c3",
                }
            },
            {
                type: 'max',
                name: '最大: ',
                position: [20, 200],
                symbol: maxIconPath,
                symbolOffset: maxSymbolOffset,
                symbolSize: (e) => {
                    let str = ![undefined, null].includes(e) ? String(e) : '';
                    let length = 60 + str.length * 6
                    return [length, 32]
                },
                itemStyle: {
                    // color: "#1980ff",
                },
                label: {
                    color: '#fff',
                    fontSize: 14,
                    fontWeight: 'bold',
                    show: true,
                    formatter: '最大: {c}',
                    offset: [0, -2]
                }
            },
            {
                name: '',
                type: 'max',
                symbol: 'emptyCircle',
                label: {show: false},
                symbolSize: 6,
            },
            {
                name: '',
                type: 'min',
                symbol: 'emptyCircle',
                label: {show: false},
                symbolSize: 6,
            }
        ];
        return {
            symbol: 'circle',
            symbolSize: 20,
            animation: false,
            silent: true,
            label: {
                show: false,
            },
            data,
        };
    };

    const renderMarkPoint = () => {
        if (timerRef.current) clearTimeout(timerRef.current);
        const chart = chartRef.current?.getEchartsInstance?.();
        timerRef.current = setTimeout(() => {
            chart.setOption({series: {markPoint: minMaxMarkPoint(dataSource,chart)}})
        }, 200)
    };

    const option = useMemo(() => {
        const config = {
            needUnit: true,
            curveCenter,
            showGridLine,
            deviceAlarmSchemes,
            showMarkLine: true,
            showPoint: true,
            chartType,
            showBoxOption,
            special
        };
        let allValDesc = {};
        let _allSensorType = special?.allSensorType?.reduce((final, curr) => {
            final[curr.id] = curr.type;
            return final;
        }, {});
        let _allPointAddress = special?.allPointAddress?.reduce((final, curr) => {
            final[curr.name] = _allSensorType[curr.sensorTypeID];
            allValDesc[curr.name] = curr.valDesc;
            return final;
        }, {});
        if (dataSource.length === 1 && SpecialType.includes(_allPointAddress[dataSource[0].sensorName])) {
            config.sensorType = _allPointAddress[dataSource[0].sensorName];
            config.special.allValDesc = allValDesc;
            return specialTypeChartOptionGenerator({dataSource, config});
        }
        let _option = optionGenerator(dataSource, null, contrast, contrastOption, smooth, config, lineDataType, predicateData, theme);
        // 将markPoint配置加入
        const chart = chartRef.current?.getEchartsInstance?.();
        if (_option?.series?.[0] && chart) {
            _option.series[0].markPoint = minMaxMarkPoint(dataSource,chart);
        }
        if (emptyOrError.empty || emptyOrError.error) {
            if (isArray(_option.yAxis)) {
                _option.yAxis.forEach(item => {
                    item.max = 100;
                    item.min = 0;
                })
            } else {
                _option.yAxis.max = 100;
                _option.yAxis.min = 0;
            }
        }
        // 加入bi模式
        if (theme === 'BI') _option = patchBIOption(_option, BI);
        return _option;
    }, [dataSource, smooth, curveCenter, chartType, predicateData,chartRef]);
    useEffect(() => {
        if (exportCanvas.exportFlag) {
            const chart = chartRef.current?.getEchartsInstance?.();
            let a = document.createElement('a');
            a.href = chart.getDataURL('image/png');
            a.download = '曲线图片.png'
            a.click();
            a.remove();
            exportCanvas.setExportFlag(null);
        }
    }, [exportCanvas.exportFlag]);
    useEffect(() => {
        chartRef.current?.resize?.();
        const chart = chartRef.current?.getEchartsInstance?.();
        function hander(params) {
            const {selected} = params;
            const count = Object.values(selected || {}).filter((item) => item).length;
            const option = cloneDeep(chart.getOption());
            const needMarkLine = count === 1;
            option.series.forEach((item, index) => {
                if (needMarkLine && selected[item.name]) {
                    item.markLine = alarmMarkLine(
                        dataSource[index],
                        index,
                        [dataSource[index]],
                        deviceAlarmSchemes,
                    );
                    // item.markPoint = minMaxMarkPoint(dataSource[index], index, [dataSource[index]]);
                } else {
                    item.markLine = {};
                    item.markPoint = {};
                }
            });
            chart.setOption(option, true);
        }
        if (!chart) return;
        renderMarkPoint();
        chart.on('legendselectchanged', hander);
        chart.on('legendselectchanged', renderMarkPoint);
        chart.on('datazoom', renderMarkPoint);
        return () => {
            chart.off('legendselectchanged', hander);
            chart.off('legendselectchanged', renderMarkPoint);
            chart.off('datazoom', renderMarkPoint);
        };
    }, [JSON.stringify(option)]);

    // 网格开关，不更新整个图表
    useEffect(() => {
        const chart = chartRef.current?.getEchartsInstance?.();
        if (!chart) return;
        const option = chart.getOption();
        // 交互指针
        const tooltip = {
            trigger: 'axis',
            axisPointer: {
                type: showGridLine ? 'cross' : 'line',
            },
        };
        // 网格线
        const axisConfig = {
            minorTick: {
                show: showGridLine,
                splitNumber: 2,
            },
            minorSplitLine: {
                // show: showGridLine,
                show: theme === 'BI' ? false : showGridLine,
                lineStyle: {
                    type: 'dashed',
                    ...(theme === 'BI' ? {color: '#38435a'} : {})
                },
            },
            splitLine: {
                show: showGridLine,
                lineStyle: {
                    ...(theme === 'BI' ? {color: '#38435a'} : {})
                },
            },
        };
        let yAxis = axisConfig;
        if (isArray(option.yAxis)) {
            yAxis = option.yAxis.map((item) => ({...axisConfig}));
        }
        let xAxis = axisConfig;
        chart.setOption({
            xAxis,
            yAxis,
            tooltip,
        });
    }, [showGridLine]);
    return <BasicChart theme={theme} ref={chartRef} option={option} notMerge
                       style={{width: '100%', height: '100%'}}/>
});

export default SingleChart;
