import moment from 'moment';
import _, {isArray} from 'lodash';
import maxIcon from './assets/最大实心.svg';
import minIcon from './assets/最小实心.svg';
import minIconDownArrow from './assets/最小实心箭头朝下.svg';
import lineChart from '@wisdom-components/basicchart/es/LineChart';
import * as echarts from 'echarts';

/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const AXIS_WIDTH = 40;
const COLOR = {
    NORMAL: '#1685FF',
    UPER: '#fa8c16',
    UPUPER: '#FF0000',
    // LOWER: '#13c2c2',
    // LOWLOWER: '#2f54eb',
    LOWER: '#fa8c16',
    LOWLOWER: '#FF0000',
    AVG: '#00B8B1',
};

const isMobile = () => {
    const userAgent = navigator.userAgent.toLowerCase();
    if (/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent)) {
        return true;
    }
    return false;
};
const returnRem = (num, base = 375) => num * (base / 375);
export const handlePx = (num, unit = '') => {
    const _isMobile = isMobile();
    const _base = document.body.clientWidth;
    let _num = _isMobile ? `${returnRem(num, _base)}` : `${num}`;
    return unit ? `${_num}${unit}` : Number(_num);
};
const PC_OPTION = {
    markPoint: {
        padding: [2, 12],
        lineHeight: 22,
        backgroundColor:
            window.globalConfig && window.globalConfig && window.globalConfig.variableTheme?.primaryColor
                ? window.globalConfig.variableTheme.primaryColor
                : '#0087F7',
        borderWidth: 1,
    },
    fontSize: 16,
    fontColor: '#ffffff',
    dataZoomHeight: 28,
};
const MOBILE_OPTION = {
    markPoint: {
        padding: [2, 6],
        lineHeight: 18,
        backgroundColor: 'rgba(255,255,255,0.6)',
        borderWidth: 0,
    },
    fontSize: handlePx(12),
    fontColor: '#0087F7',
    dataZoomHeight: 20,
};
const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION;
/**
 * 图表系列名称格式化
 *
 * @param {any} data
 * @param {boolean} contrast 是否为同期对比
 * @param {any} contrastOption 同期对比周期配置, day|month
 * @param nameWithSensor
 * @param {boolean} isSingle 是否是单设备，单设备的名称不带设备名
 * @returns
 */
const nameFormatter = (data, contrast, contrastOption, nameWithSensor, isSingle) => {
    const {equipmentName, sensorName, unit, dataModel, dateFrom, dateTo} = data;
    let name = nameWithSensor ? (isSingle?`${sensorName}`:`${equipmentName}-${sensorName}`) : equipmentName;
    if (contrast) {
        const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
        name = `${name}-${time}`;
    }
    return name;
};

/**
 * 图表系列数据格式化
 *
 * @param {any} data
 * @param {boolean} contrast 是否为同期对比
 * @param {any} contrastOption 同期对比周期配置, day|month
 * @returns 图表系列数据, [[DateTime, value]]
 */
const dataAccessor = (data, contrast, contrastOption) => {
    const dataModel = data?.dataModel ?? [];
    const formatStr = contrastOption === 'day' ? '2020-01-01 HH:mm:ss' : '2020-01-DD HH:mm:ss';
    return dataModel
        .filter((item) => item.sensorName !== '是否在线')
        .map((item) => {
            const time = contrast ? moment(item.pt).format(formatStr) : item.pt;
            return [moment(time).valueOf(), item.pv];
        });
};

/**
 * 面积图配置(目前默认曲线图)
 *
 * @param {any} data 数据项
 * @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
 */
const areaStyleFormatter = (data) => {
    const {sensorName} = data;
    return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
};

/**
 * 数据项中指标值最小最大值
 *
 * @param {any} data 数据项
 * @returns
 */
const minMax = (data) => {
    const {dataModel} = data;
    let min = Number.MAX_SAFE_INTEGER;
    let max = Number.MIN_SAFE_INTEGER;
    dataModel.forEach((item) => {
        min = Math.min(min, item.pv ?? 0);
        max = Math.max(max, item.pv ?? 0);
    });
    return [min, max];
};

const markLineItem = (name, value, color) => {
    return {
        name: name,
        yAxis: value,
        value: value,
        lineStyle: {
            color: color || '#000',
        },
        label: {
            position: 'insideEndTop',
            color: color || '#000',
            formatter: function () {
                return `${name}:${value}`;
            },
        },
    };
};

export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
    // 只有一个数据曲线时显示markline
    if (!dataItem || !schemes || dataSource.length !== 1) return {};
    const {deviceType, stationCode, sensorName, decimalPoint} = dataItem;
    const curSchemes = schemes.filter(
        (item) =>
            item.deviceCode === stationCode &&
            item.sensorName === sensorName &&
            item.valueType === '直接取值',
    );
    const data = [];
    curSchemes.forEach((scheme) => {
        const {hLimit, hhLimit, lLimit, llLimit} = scheme;
        lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16'));
        hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
        llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
        hhLimit !== null && hhLimit !== void 0 && data.push(markLineItem('高高限', hhLimit, '#FF0000'));
    });
    data.push({
        name: '平均线',
        type: 'average',
        lineStyle: {
            color: '#00b8b1',
            type: 'solid',
        },
        label: {
            position: 'insideEndTop',
            color: '#00b8b1',
            formatter: function (param) {
                return `平均值:${param.value}`;
            },
        },
    });
    return {
        symbol: ['none', 'none'],
        data,
    };
};

export const minMaxMarkPoint = (dataItem, index, dataSource) => {
    const _isMobile = isMobile();
    // 只有一个数据曲线时显示markline
    if (!dataItem || dataSource.length !== 1) return {};
    const data = [
        {
            type: 'min',
            value: null,
            name: '最小: ',
            symbol: `image://${minIcon}`,
            symbolOffset: [0, 18],
        },
        {
            type: 'max',
            value: null,
            name: '最大: ',
            symbol: `image://${maxIcon}`,
            symbolOffset: [0, -16],
        },
    ];
    return {
        label: {
            show: false,
        },
        symbolSize: [49, 31],
        data,
    };
};

/**
 * 坐标轴添加网格线配置
 *
 * @param {any} axis
 */
export const decorateAxisGridLine = (axis, showGrid) => {
    if (!axis) return;
    axis.minorTick = {
        lineStyle: {
            color: '#e2e2e2',
        },
        ...(axis.minorTick || {}),
        show: showGrid,
        splitNumber: 2,
    };
    axis.minorSplitLine = {
        lineStyle: {
            color: '#e2e2e2',
            type: 'dashed',
        },
        ...(axis.minorSplitLine || {}),
        show: showGrid,
    };
    axis.splitLine = {
        ...(axis.splitLine || {}),
        show: showGrid,
    };
};

/**
 * 坐标轴添加离线区间
 *
 * @param {any} dataItem
 */
export const offlineArea = (dataItem) => {
    if (!dataItem) return {};
    const {dataModel} = dataItem;
    let datas = new Array();
    let offlineData = [];
    let hasOffline = false;
    dataModel.forEach((item, index) => {
        if (!item.pv && !hasOffline) {
            offlineData = [
                {
                    name: '离线',
                    xAxis: new Date(item.pt),
                    label: {show: !datas?.length},
                },
            ];
            hasOffline = true;
        } else if (item.pv && hasOffline) {
            offlineData.push({
                xAxis: new Date(item.pt),
            });
            datas.push(offlineData);
            offlineData = [];
            hasOffline = false;
        }
    });
    return {
        itemStyle: {
            color: '#eee',
            opacity: 0.6,
        },
        data: datas,
    };
};
// tooltip 模板
const headTemplate = (param, opt) => {
    if (!param) return '';
    const {name, axisValueLabel, axisType, axisValue} = param;
    const timeFormat =
        opt && opt.contrast
            ? opt.contrastOption === 'day'
                ? 'HH:mm:ss'
                : 'DD日HH时'
            : 'YYYY-MM-DD HH:mm:ss';
    const text =
        axisType === 'xAxis.time' ? moment(axisValue).format(timeFormat) : name || axisValueLabel;
    return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom:${handlePx(
        5,
        'px',
    )}; padding-bottom: ${handlePx(5, 'px')};">${text}</div>`;
};
const seriesTemplate = (param, unit) => {
    if (!param || param.seriesName === '自定义') return '';
    const {value, encode} = param;
    // const val = value[encode.y[0]];
    const _unit = unit || '';
    const color = '#008CFF';
    if (!isArray(value))
        return ` <div style="display: flex; align-items: center;">
            <span style="${
            isMobile()
                ? 'width: ' +
                handlePx(90, 'px') +
                ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
                : ''
        }">${param.seriesName}</span>
            <span style="display:inline-block;">：</span>
            <span style="color:${color};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value?.toFixed(3) ?? '-'
        }</span>
            <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
        </div>`;
    return param.componentSubType !== 'candlestick'
        ? `<div style="display: flex; align-items: center;">
              <span style="${
            isMobile()
                ? 'width: ' +
                handlePx(90, 'px') +
                ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
                : ''
        }">${param.seriesName}</span><span style="display:inline-block;">：</span>
              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value[1] ?? '-'
        }</span>
              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
            </div>`
        : `
            <div style="display: flex; align-items: center;">
              <span>首值</span><span style="display:inline-block;">：</span>
              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value[1] ?? '-'
        }</span>
              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
            </div>
            <div style="display: flex; align-items: center;">
              <span>尾值</span><span style="display:inline-block;">：</span>
              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value[2] ?? '-'
        }</span>
              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
            </div>
            <div style="display: flex; align-items: center;">
              <span>周期最小值</span><span style="display:inline-block;">：</span>
              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value[3] ?? '-'
        }</span>
              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
            </div>
            <div style="display: flex; align-items: center;">
              <span>周期最大值</span><span style="display:inline-block;">：</span>
              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
            value[4] ?? '-'
        }</span>
              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
            </div>
          `;
};
const tooltipAccessor = (unit, contrastOption) => {
    return {
        formatter: function (params, ticket, callback) {
            let tooltipHeader = '';
            let tooltipContent = '';
            if (isArray(params)) {
                tooltipHeader = headTemplate(params[0], contrastOption);
                params.forEach((param) => {
                    tooltipContent += seriesTemplate(param, unit?.[param?.seriesIndex]);
                });
            } else {
                tooltipHeader = headTemplate(params, contrastOption);
                tooltipContent += seriesTemplate(params, unit?.[params?.seriesIndex]);
            }
            return `
      <div>
        ${tooltipHeader}
        <div>${tooltipContent}</div>
      </div>
    `;
        },
    };
};
// 处理特殊业务：1. 频率；2. 是否在线（暂时不上）
const handleSpecial1 = (special, dataSource) => {
    // 频率部分的业务
    const _colorMap = {
        变频: '#1685ff',
        工频: '#00d0c7',
        运行: '#1685ff',
        故障: '#ff6b37',
        停止: '#aeaeae',
    };
    let _special1 = special?.special1 ?? {};
    let _valDesc = _special1?.valDesc ?? {};
    let _data = dataSource.find((item) => item.sensorName === _special1.name);
    let _markAreaData = [];
    let _pieces =
        _data?.dataModel
            ?.reduce((final, cur, index) => {
                let _pt = moment(cur.pt).valueOf();
                let _length = final.length;
                if (_colorMap[_valDesc[cur.pv]]) {
                    if (index === 0) {
                        final.push({
                            lte: _pt,
                            gte: 0,
                            color: _colorMap[_valDesc[cur.pv]],
                            value: cur.pv,
                            text: _valDesc[cur.pv],
                        });
                    } else {
                        if (cur.pv === final[_length - 1].value) {
                            final[_length - 1].lte = _pt;
                        } else {
                            final.push({
                                lte: _pt,
                                gte: final[_length - 1].lte,
                                color: _colorMap[_valDesc[cur.pv]],
                                value: cur.pv,
                                text: _valDesc[cur.pv],
                            });
                        }
                    }
                }
                return final;
            }, [])
            .map((item) => {
                _markAreaData.push([
                    {
                        xAxis: item.gte,
                        itemStyle: {
                            // color: item.color
                            color: {
                                type: 'linear',
                                x: 0,
                                y: 0,
                                x2: 0,
                                y2: 1,
                                colorStops: [
                                    {
                                        offset: 0,
                                        color: item.color, // 0% 处的颜色
                                    },
                                    {
                                        offset: 1,
                                        color: item.color, // 100% 处的颜色
                                    },
                                ],
                                global: false, // 缺省为 false
                            },
                        },
                        name: item.text,
                        label: {show: true},
                    },
                    {
                        xAxis: item.lte,
                        itemStyle: {
                            color: item.color,
                        },
                    },
                ]);
                delete item.value;
                return item;
            }) ?? [];
    let _final = {};
    if (_markAreaData.length) {
        _final.visualMap = {
            type: 'piecewise',
            show: false,
            dimension: 0,
            seriesIndex: 0,
            pieces: _pieces,
        };
    }
    if (_pieces.length) {
        _final.markArea = {
            silent: true,
            itemStyle: {
                opacity: 0.1,
            },
            data: _markAreaData,
        };
    }
    return _final;
};
// 生成x坐标
const returnXAxis = ({
                         dataSource,
                         contrast,
                         contrastOption,
                         nameWithSensor,
                         showMarkLine,
                         deviceAlarmSchemes,
                         showPoint,
                         restOption,
                         smooth,
                         special,
                         yAxis,
                     }) => {
    // 根据"指标名称"分类yAxis
    const yAxisInterator = (() => {
        const map = new Map();
        let current = -1;
        const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
        return {get};
    })();
    let _offlineData = [];
    // 生成visualMap、markArea
    let {visualMap, markArea} = handleSpecial1(special, dataSource);
    let _filterArr = ['是否在线'];
    if (special?.special1?.name) {
        _filterArr.push(special.special1.name);
    }
    // 生成series
    // 单设备情况下，不显示设备名称
    let deviceNumber = dataSource?.reduce((final, cur) => {
        if (!final.includes(cur.stationCode)) final.push(cur.stationCode);
        return final
    }, [])?.length;
    let series = dataSource
        .filter((item) => {
            if (item.sensorName === '是否在线') {
                _offlineData.push(item);
            }
            return !_filterArr.includes(item.sensorName);
        })
        .map((item, index) => {
            const {sensorName, unit} = item;
            const name = nameFormatter(item, contrast, contrastOption, nameWithSensor, deviceNumber === 1);
            const data = dataAccessor(item, contrast, contrastOption);
            const type = 'line';
            const areaStyle = areaStyleFormatter(item);
            const _index = yAxis.findIndex((item) => item.name === unit);
            const yAxisIndex = _index > -1 ? _index : 0;
            const markLine = showMarkLine
                ? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes)
                : {};
            const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {};
            // let markArea = null;
            // 需求变更：设备离线改用“是否在线”的数据，离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55
            // 暂时注释，离线逻辑需要再确认 2023-09-15
            /*            let _offlineAreasData = _offlineData
                                              .find((offline) => offline.stationCode === item.stationCode);
                                          let offlineAreas = offlineArea(_offlineAreasData);
                                          if (offlineAreas.data?.length) {
                                              restOption.markArea = null;
                                              markArea = offlineAreas;
                                          }*/
            // 需求新增：增加频率业务
            return {
                notMerge: true,
                name,
                type,
                data,
                areaStyle,
                yAxisIndex,
                smooth,
                unit,
                markLine,
                markPoint,
                markArea,
            };
        });
    // 由于series更新后，没有的数据曲线仍然停留在图表区上，导致图表可视区范围有问题
    const min = Math.min(
        ...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined),
    );
    const max = Math.max(
        ...series
            .map((item) => item.data?.[item.data.length - 1]?.[0])
            .filter((item) => item !== undefined),
    );
    return {
        xAxis: {
            type: 'time',
            min,
            max,
            axisLabel: {
                formatter: contrast
                    ? contrastOption === 'month'
                        ? '{dd}日'
                        : '{HH}:{mm}'
                    : {
                        year: '{yyyy}',
                        month: '{MMM}',
                        day: '{d}日',
                        hour: '{HH}:{mm}',
                        minute: '{HH}:{mm}',
                        second: '{HH}:{mm}:{ss}',
                        none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}',
                    },
            },
        },
        series,
        visualMap,
    };
};
const handleDefault = (config, cusOption) => {
    const needUnit = _.get(config, 'needUnit', false);
    const curveCenter = _.get(config, 'curveCenter', false);
    const nameWithSensor = _.get(config, 'nameWithSensor', true);
    const showGridLine = _.get(config, 'showGridLine', true);
    const showMarkLine = _.get(config, 'showMarkLine', false);
    const showPoint = _.get(config, 'showPoint', false);
    const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []);
    const chartType = _.get(config, 'chartType', null);
    const showBoxOption = _.get(config, 'showBoxOption', false);
    // 自定义属性
    const restOption = _.pick(cusOption, ['title', 'legend']);
    const special = _.get(config, 'special', {});
    return {
        needUnit,
        curveCenter,
        nameWithSensor,
        showGridLine,
        showMarkLine,
        showPoint,
        deviceAlarmSchemes,
        chartType,
        showBoxOption,
        restOption,
        special,
    };
};
const handleMaxValue = (value) => {
    if (value <= 1) return value.toFixed(2);
    if (value >= 100000) return `${(value / 1000).toFixed(2)}k`;
    return value.toFixed(2);
};
const reduceYAxis = (arr, dataSource) => {
    let _offsetValue = [];
    // 1. 合并相同单位的坐标轴
    let _arr = arr.reduce((final, cur) => {
        let _key = cur.name === null ? 'null' : cur.name;
        if (!final[_key]) {
            final[_key] = cur;
        }
        return final;
    }, {});
    // 2. 合并相同单位的数据，找出最大值
    let _maxValueArr = Object.values(
        dataSource.reduce((final, cur) => {
            let _key = cur.sensorName === null ? 'null' : cur.sensorName;
            let _maxValue = cur.dataModel.reduce((final, cur) => {
                // eslint-disable-next-line no-param-reassign
                if (cur.pv > final) final = cur.pv;
                return final;
            }, 0);
            if (final[_key] === undefined) {
                final[_key] = _maxValue;
            } else {
                final[_key] = Math.max([final[_key], _maxValue]);
            }
            return final;
        }, {}),
    );
    // 3. 合并，生成Y轴配置
    return Object.values(_arr).map((item, index) => {
        let _key = item.name === null ? 'null' : item.name;
        let _lastAxisNumber = _maxValueArr[index - 2];
        let _baseOffset = _offsetValue[index - 2] ?? 0;
        let _finalOffset =
            (_lastAxisNumber !== undefined // 没有相邻的轴
                ? (_lastAxisNumber === 0 ? 20 : _lastAxisNumber.toFixed(2).replaceAll('.', '').length) * 12
                : 0) + _baseOffset;
        _offsetValue.push(_finalOffset);
        return {
            ...item,
            offset: _finalOffset,
            position: index % 2 === 0 ? 'left' : 'right',
            nameTextStyle: {
                align: index % 2 === 0 ? 'right' : 'left',
            },
        };
    });
};

/**
 * 1. 生成常规的yAxis配置； 2. 处理sensorType为状态值的指标，生成yAxis配置
 *
 * @param {array} dataSource 数据源
 * @param {boolean} needUnit 是否显示单位。
 * @param {boolean} curveCenter 曲线是否居中。
 * @param {boolean} showGridLine 是否显示网格线。
 * @returns {object} 返回左右轴的margin、yAxis的配置。
 */
const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => {
    const yAxisMap = new Map();
    // 1. 找出最大值; 2. 计算出y轴最大宽度动态计算偏移距离；
    dataSource.forEach((item, index) => {
        const {sensorName, unit} = item;
        const key = sensorName;
        if (!yAxisMap.has(key)) {
            const axis = {
                type: 'value',
                name: needUnit ? unit : null,
                axisLabel: {
                    formatter: (value) => {
                        return handleMaxValue(value);
                    },
                },
                axisLine: {
                    show: true,
                },
                minorTick: {
                    lineStyle: {
                        color: '#e2e2e2',
                    },
                },
                minorSplitLine: {
                    lineStyle: {
                        color: '#e2e2e2',
                        type: 'dashed',
                    },
                },
            };
            yAxisMap.set(key, axis);
        }
        // 曲线居中
        if (curveCenter && item.dataModel && item.dataModel.length > 0) {
            const [min, max] = minMax(item);
            const axis = yAxisMap.get(key);
            axis.min = axis.min === void 0 ? min : Math.min(min, axis.min);
            axis.max = axis.max === void 0 ? max : Math.max(max, axis.max);
        }
        // 网格显示
        const axis = yAxisMap.get(key);
        decorateAxisGridLine(axis, showGridLine);
    });
    const yAxis =
        yAxisMap.size > 0 ? reduceYAxis([...yAxisMap.values()], dataSource) : {type: 'value'};
    const leftNum = Math.ceil(yAxisMap.size / 2);
    const rightNum = Math.floor(yAxisMap.size / 2);
    return {leftNum, rightNum, yAxis};
};
/**
 * 1. 最后的配置处理、合并
 *     dataZoom 缩放
 *     xAxis.minInterval X轴的最小间隔
 *     legend legend配置
 *
 * @param {object} restOption 额外配置
 * @param {object} xAxis X轴的配置
 * @param {array} legendData Legend数组
 * @param {string} chartType 线型 lineChart|boxChart
 * @param {boolean} contrast 是否为同期对比
 * @param {string} contrastOption 同期对比周期配置, day|month
 * @param {object} config 其他的配置
 */
const assignOptions = (
    restOption,
    xAxis,
    legendData,
    chartType,
    contrast,
    contrastOption,
    config,
) => {
    restOption.dataZoom = [
        {
            show: true,
            bottom: 20,
            start: 0,
            end: 100,
            height: config.isMultiple ? 20 : 28,
            type: 'inside',
            zoomOnMouseWheel: true,
            filterMode: chartType === 'lineChart' ? 'none' : 'weakFilter',
        },
        {
            show: true,
            bottom: 20,
            start: 0,
            end: 100,
            height: config.isMultiple ? 20 : 28,
            type: 'slider',
            zoomOnMouseWheel: true,
            labelFormatter: function (e) {
                let _formatterStr = 'YYYY-MM-DD HH:mm:ss';
                if (contrast) {
                    if (contrastOption === 'day') _formatterStr = 'HH:mm';
                    if (contrastOption === 'month') _formatterStr = 'MM月DD日 HH时';
                }
                return moment(e).format(_formatterStr);
            },
        },
    ];
    xAxis.minInterval = 3600 * (1 * 1000);
    if (legendData) {
        restOption.legend = {
            ...{
                show: true,
                right: 10,
                top: 30,
                icon: 'rect',
                itemWidth: 14,
                itemHeight: 8,
                itemGap: 20,
            },
            ...restOption.legend,
            ...{data: legendData},
        };
    }
};

const returnMaxOrMinNumber = (dataSource, type) => {
    let _obj = null;
    if (type === 'period' && dataSource?.[0]?.dataModel?.length) {
        let _length = dataSource?.[0]?.dataModel?.length;
        let _first = dataSource?.[0]?.dataModel[0]?.pt;
        let _last = dataSource?.[0]?.dataModel[_length - 1]?.pt;
        return ['展示时段: ', _first, _last, type];
    }
    dataSource?.[0]?.dataModel
        .filter((item) => item.pv !== null)
        .forEach((item) => {
            if (!_obj) {
                _obj = item;
            } else {
                if (type === 'min') {
                    if (item.pv < _obj.pv) {
                        _obj = item;
                    }
                }
                if (type === 'max') {
                    if (item.pv > _obj.pv) {
                        _obj = item;
                    }
                }
            }
        });
    let _value = [];
    if (_obj?.pt) {
        _value = [moment(_obj.pt).valueOf(), _obj.pv];
        let _img = type === 'max' ? maxIcon : minIconDownArrow;
        _value.push(_img);
        _value.push(type);
        // 把最大值最小值都push进去，方便计算
    }
    return _value;
};

const handleGrid = (dataSource, needUnit, leftNum, rightNum, chartType) => {
    // 如果是单曲线，_grid的top需要一行的高度，用来放置最值最小值
    let _base = 60;
    let _topForUnit = needUnit ? 20 : 0;
    return {
        top: _base + _topForUnit,
        left: 30,
        right: 10,
        bottom: 60,
        containLabel: true,
    };
};
const renderItem = (params, api) => {
    let _base = params.dataIndex;
    let _baseChartWidth = 10;
    let _numberStringWidth =
        _base === 1 && api.value(3) === 'max'
            ? String(api.value(4) || 0).length * _baseChartWidth
            : String(api.value(1)).length * _baseChartWidth;
    let _left = 30;
    let _baseWidth = 190 + _numberStringWidth;
    let _imgWidth = 45;
    let _dateWidth = 128;
    let _imageX = _left + _base * _baseWidth;
    let _timeX = _left + _base * _baseWidth + _imgWidth;
    let _valueX = _left + _base * _baseWidth + _imgWidth + _dateWidth;
    let _color = api.value(3) === 'min' ? '#05C2BC' : '#1685FF';
    let topValue = 25;
    let _trimmer = -2;
    return {
        type: 'group',
        children: [
            {
                type: 'image',
                style: {
                    image: api.value(2),
                    textVerticalAlign: 'middle',
                    y: -6,
                },
                position: [_imageX, topValue],
            },
            {
                type: 'text',
                style: {
                    text: moment(api.value(0)).format('YYYY-MM-DD HH:mm:ss') + ': ',
                    textVerticalAlign: 'top',
                },
                position: [_timeX, topValue + _trimmer],
            },
            {
                type: 'text',
                style: {
                    text: api.value(1),
                    textVerticalAlign: 'middle',
                    fill: _color,
                    font: 'bolder 16px cursive',
                    lineWidth: 10,
                    y: 3,
                },
                position: [_valueX, topValue + _trimmer],
            },
        ],
    };
};
const returnCustomSeries = (dataSource) => {
    let _maxNumber = returnMaxOrMinNumber(dataSource, 'max');
    let _minNumber = returnMaxOrMinNumber(dataSource, 'min');
    if (!_maxNumber.length && !_minNumber.length) return false;
    // let _period = returnMaxOrMinNumber(dataSource, 'period');
    // 需要将最大值最小分别传入，后续计算图例位置需要，先min后max
    let _max = _maxNumber[1];
    let _min = _minNumber[1];
    [_maxNumber, _minNumber].forEach((item) => {
        item.push(_min);
        item.push(_max);
    });
    return {
        name: '自定义',
        type: 'custom',
        renderItem: renderItem,
        data: [_minNumber, _maxNumber],
    };
};

const renderStatusItem = (params, api) => {
    var categoryIndex = api.value(0);
    var start = api.coord([api.value(1), categoryIndex]);
    var end = api.coord([api.value(2), categoryIndex]);
    var height = api.size([0, 1])[1] * 0.4;
    var rectShape = echarts.graphic.clipRectByRect(
        {
            x: start[0],
            y: start[1] - height / 2,
            width: end[0] - start[0],
            height: height,
        },
        {
            x: params.coordSys.x,
            y: params.coordSys.y,
            width: params.coordSys.width,
            height: params.coordSys.height,
        },
    );
    return (
        rectShape && {
            type: 'rect',
            transition: ['shape'],
            shape: rectShape,
            style: api.style(),
        }
    );
};

/**
 * 图表配置项生成
 *
 * @param {any} dataSource 数据源
 * @param {any} cusOption 自定义属性
 * @param {any} contrast 是否为同期对比
 * @param {any} contrastOption 同期对比周期配置, day|month
 * @param {any} smooth Ture/false, 曲线/折线
 * @param {any} config 额外配置信息
 */

const optionGenerator = (
    dataSource,
    cusOption,
    contrast,
    contrastOption,
    smooth,
    config,
    lineDataType = '',
) => {
    // 1. 处理配置，配置分配默认值；
    const {
        needUnit,
        curveCenter,
        nameWithSensor,
        showGridLine,
        showMarkLine,
        showPoint,
        deviceAlarmSchemes,
        chartType,
        showBoxOption,
        restOption,
        special,
    } = handleDefault(config, cusOption);
    const {leftNum, rightNum, yAxis} = handleYAxis({
        dataSource,
        needUnit,
        curveCenter,
        showGridLine,
    });
    let {xAxis, series, visualMap} = returnXAxis({
        dataSource,
        contrast,
        contrastOption,
        nameWithSensor,
        showMarkLine,
        deviceAlarmSchemes,
        showPoint,
        smooth,
        restOption,
        special,
        yAxis,
    });
    // 3. 判断是否开启网格；
    const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType);
    decorateAxisGridLine(xAxis, showGridLine);
    const tooltipTimeFormat = !contrast
        ? 'YYYY-MM-DD HH:mm:ss'
        : contrastOption === 'day'
            ? 'HH:mm'
            : 'DD HH:mm';
    let tooltip = {};
    // 增加箱线图的逻辑，单曲线才存在该逻辑
    if (chartType && showBoxOption && !special?.special1?.name) {
        if (chartType === 'boxChart' && lineDataType === '特征曲线') {
            const otherData =
                dataSource?.[0]?.dataModel.map((item) => {
                    const {firstPV, lastPV, maxPV, minPV, pt} = item;
                    return [moment(pt).valueOf(), firstPV, lastPV, minPV, maxPV];
                }) || []; //当存在othersData的时候，只是单曲线
            xAxis = {type: 'time'};
            decorateAxisGridLine(xAxis, showGridLine);
            let unit = [];
            series = series.map((item) => {
                if (item.unit) unit.push(item.unit);
                item.areaStyle = null;
                return {
                    ...item,
                    z: 9,
                    showSymbol: false,
                    lineStyle: {
                        ...(item.lineStyle ?? {}),
                        width: 1,
                        opacity: 0.4
                    }
                };
            });
            // 箱线图去除曲线 2023年10月17日
            series.push({
                type: 'candlestick',
                name: '箱线图',
                symbol: 'none',
                data: otherData,
                z: 10,
                itemStyle: {
                    color: '#FFA200',
                    color0: '#44CD00',
                    borderColor: '#FFA200',
                    borderColor0: '#44CD00',
                },
            });
            tooltip = tooltipAccessor(unit);
        }
        if (chartType === 'lineChart' || lineDataType === '原始曲线') {
            let _maxData = [];
            let _minData = [];
            let _currentYear = moment().format('YYYY');
            const formatStr =
                contrastOption === 'day'
                    ? `${_currentYear}-01-01 HH:mm:00`
                    : `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比，把日期拉到同一区间
            let _maxValues = [];
            /** 生成泳道图，分两种情况 1. 当最大值最小值都是正数时； 2. 当最大值小于零时（此时，最小值一定小于零）； */
            dataSource?.[0]?.dataModel.forEach((item) => {
                const {firstPV, lastPV, maxPV, minPV, pt} = item;
                _maxValues.push(maxPV);
                let time = contrast ? moment(pt).format(formatStr) : pt;
                _maxData.push([
                    moment(time).valueOf(),
                    (maxPV > 0 ? maxPV - minPV : minPV - maxPV).toFixed(2),
                ]);
                _minData.push([moment(time).valueOf(), maxPV > 0 ? minPV : maxPV]);
            }); //当存在othersData的时候，只是单曲线
            // xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD HH:mm:ss'))};
            xAxis = {type: 'time'};
            decorateAxisGridLine(xAxis, showGridLine);
            let _unit = '';
            series = series.map((item) => {
                _unit = item.unit ?? '';
                item.areaStyle = null;
                return {...item, showSymbol: false};
            });
            [[..._minData], [..._maxData]].forEach((item, index) => {
                series.push({
                    name: index === 0 ? '周期最小值' : '周期最大值',
                    type: 'line',
                    data: item,
                    lineStyle: {
                        opacity: 0,
                    },
                    ...(index !== 0
                        ? {
                            areaStyle: {
                                color: series?.[0]?.itemStyle?.color ?? '#65a0d1',
                                opacity: 0.2,
                            },
                        }
                        : {}),
                    stack: 'confidence-band',
                    symbol: 'none',
                });
            });
            tooltip = {
                trigger: 'axis',
                formatter: (e) => {
                    return `<div>
                    ${headTemplate(e[0])}
                    <div>
                        <div style="display: flex; align-items: center;">
                              <span style="${
                        isMobile()
                            ? 'width: ' +
                            handlePx(90, 'px') +
                            ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
                            : ''
                    }">${
                        e[0].seriesName
                    }</span><span style="display:inline-block;">：</span>
                              <span style="color: ${COLOR.NORMAL};margin: 0 ${handlePx(
                        5,
                        'px',
                    )} 0 auto;">${e[0]?.value?.[1] ?? '-'}</span>
                              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
                            </div>
                            <div style="display: ${
                        lineDataType === '特征曲线' ? 'flex' : 'none'
                    }; align-items: center;">
                              <span>周期最小值</span><span style="display:inline-block;">：</span>
                              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
                        5,
                        'px',
                    )} 0 auto;">${e?.[1]?.value?.[1] ?? '-'}</span>
                              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
                            </div>
                            <div style="display: ${
                        lineDataType === '特征曲线' ? 'flex' : 'none'
                    }; align-items: center;">
                              <span>周期最大值</span><span style="display:inline-block;">：</span>
                              <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
                        5,
                        'px',
                    )} 0 auto;">${_maxValues[e?.[2]?.dataIndex] ?? '-'}</span>
                              <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
                            </div>
                        </div>
                    </div>`;
                },
            };
        }
        // 单曲线需要标记最大值、最小值的情况下，需要增加自定义的series，将最大最小值显示在图表上
        if (dataSource?.[0]?.dataModel?.length && chartType === 'lineChart') {
            let _dataSource = dataSource?.filter((item) => item?.dataModel?.length);
            if (_dataSource?.length) {
                let _customSeries = returnCustomSeries(dataSource);
                if (_customSeries) {
                    series.push(_customSeries);
                }
            }
        }
    } else {
        tooltip = tooltipAccessor(
            series.map((item) => item.unit),
            {contrastOption, contrast},
        );
    }
    tooltip.timeFormat = tooltipTimeFormat;
    let _legendData = series
        .filter((item) => !['周期最大值', '周期最小值', '自定义'].includes(item.name)) // legend中，过滤掉辅助业务的legend
        .map((item) => item.name);
    assignOptions(restOption, xAxis, _legendData, chartType, contrast, contrastOption, config);
    let _options = {
        yAxis,
        grid,
        xAxis,
        series,
        tooltip,
        visualMap,
        ...restOption,
    };
    return _options;
};

export default optionGenerator;

const handleDataSource = (dataSource) => {
    let _temp = null;
    let _data = [];
    let _dataLength = dataSource[0].dataModel.length;
    dataSource[0].dataModel.forEach((item, index) => {
        if (index === 0) {
            _data.push(item);
        } else if (index === _dataLength - 1) {
            _data.push(item);
        } else {
            if (_temp.pv !== item.pv) {
                _data.push(item);
            }
        }
        _temp = item;
    });
    return _data;
};
const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => {
    let color = '';
    let name = '';
    let value1 = '';
    let value2 = '';
    // 1. valDesc
    if (sensorType === '状态值') {
        const _colorMap = {
            变频: '#1685ff',
            工频: '#00d0c7',
            运行: '#1685ff',
            故障: '#ff6b37',
            停止: '#aeaeae',
        };
        let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => {
            let _arr = cur.split(':');
            final[_arr[0]] = _arr[1];
            return final;
        }, {});
        name = _valDescMap[data1.pv || 0];
        color = _colorMap[name];
    }

    //2. 开关量
    if (sensorType === '开关值') {
        const _switchColorMap = {
            0: '#aeaeae',
            1: '#1685ff',
        };
        const _switchNameMap = {
            0: '关',
            1: '开',
        };
        name = _switchNameMap[data1.pv || 0];
        color = _switchColorMap[data1.pv || 0];
    }

    value1 = moment(data1.pt).valueOf();
    value2 = moment(data2.pt).valueOf();
    return {color, value1, value2, name};
};
const handleDataToSeries = (special, sensorName, sensorType, data) => {
    let _data = [];
    let _legend = [];
    data.forEach((item, index) => {
        if (index === data.length - 1) return;
        let {color, value1, value2, name} = handleSpecial2(
            special,
            sensorName,
            sensorType,
            item,
            data[index + 1],
        );
        if (!_legend.includes(name)) _legend.push(name);
        _data.push({
            itemStyle: {normal: {color}},
            name: name,
            value: [0, value1, value2, `${item.pt}-${data[index + 1].pt}`],
        });
    });
    return {data: _data, legend: _legend};
};

const specialTypeChartOptionGenerator = ({
                                             dataSource,
                                             cusOption,
                                             contrast,
                                             contrastOption,
                                             smooth,
                                             config,
                                         }) => {
    const {special, sensorType} = config;
    const {allSensorType, allPointAddress} = special;
    // 处理原始数据，处理数据为后series数据
    const sensorName = dataSource[0].sensorName;
    let _data = handleDataSource(dataSource);
    let {data, legend} = handleDataToSeries(special, sensorName, sensorType, _data);
    // 1. x/y轴
    let xAxis = {
        type: 'time',
        axisLabel: {
            formatter: contrast
                ? contrastOption === 'month'
                    ? '{dd}日'
                    : '{HH}:{mm}'
                : {
                    year: '{yyyy}',
                    month: '{MMM}',
                    day: '{MMM}{d}日',
                    hour: '{HH}:{mm}',
                    minute: '{HH}:{mm}',
                    second: '{HH}:{mm}:{ss}',
                    none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}',
                },
        },
        minorTick: {
            lineStyle: {
                color: '#e2e2e2',
            },
            show: true,
            splitNumber: 2,
        },
        minorSplitLine: {
            lineStyle: {
                color: '#e2e2e2',
                type: 'dashed',
            },
            show: true,
        },
        splitLine: {
            show: true,
        },
        minInterval: 3600 * 1000,
    };
    let yAxis = {
        data: [dataSource[0].sensorName],
        axisLine: {
            show: true,
        },
        minorTick: {
            lineStyle: {
                color: '#e2e2e2',
            },
            show: true,
            splitNumber: 2,
        },
        minorSplitLine: {
            lineStyle: {
                color: '#e2e2e2',
                type: 'dashed',
            },
            show: true,
        },
        splitLine: {
            show: true,
        },
    };
    //2. series
    let series = [
        {
            type: 'custom',
            renderItem: renderStatusItem,
            itemStyle: {
                opacity: 0.8,
            },
            encode: {
                x: [1, 2],
                y: 0,
            },
            data,
        },
        ...legend.map((item) => {
            let _map = {
                变频: '#1685ff',
                工频: '#00d0c7',
                运行: '#1685ff',
                故障: '#ff6b37',
                停止: '#898989',
                关: '#cacaca',
                开: '#1685ff',
            };
            return {
                type: 'custom',
                name: item,
                color: _map[item],
                renderItem: () => {
                },
            };
        }),
    ];
    let grid = {
        top: 80,
        left: 30,
        right: 10,
        bottom: 60,
        containLabel: true,
    };
    let legendConfig = {
        show: true,
        data: legend,
        selectedMode: false,
        right: 10,
        top: 30,
        icon: 'rect',
        itemWidth: 14,
        itemHeight: 8,
        itemGap: 20,
    };
    let _option = {
        xAxis,
        yAxis,
        grid,
        series,
        legend: legendConfig,
        tooltip: {
            trigger: 'item',
            formatter: function (params) {
                return params.marker + params.name + ': ' + params?.value?.[3];
            },
        },
        dataZoom: [
            {
                type: 'slider',
                filterMode: 'weakFilter',
                showDataShadow: false,
                labelFormatter: '',
            },
            {
                type: 'inside',
                filterMode: 'weakFilter',
            },
        ],
    };
    return _option;
};
export {specialTypeChartOptionGenerator};
