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
 * @returns
 */
const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
  const { equipmentName, sensorName, unit, dataModel, dateFrom, dateTo } = data;
  let name = nameWithSensor ? `${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',
    停止: '#666666',
  };
  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 (_length === 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].gte,
                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 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);
      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');
  // 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, showSymbol: false };
      });
      // 箱线图去除曲线 2023年10月17日
      series = [
        {
          type: 'candlestick',
          name: '箱线图',
          symbol: 'none',
          data: otherData,
          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 _customSeries = returnCustomSeries(dataSource);
      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;
  // handleSpecial2()
  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 returnLegend = (sensorType) => {
  const _colorMap = {
    变频: '#1685ff',
    工频: '#00d0c7',
    运行: '#1685ff',
    故障: '#ff6b37',
    停止: '#666666',
  };
};
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',
      停止: '#666666',
    };
    let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => {
      let _arr = cur.split(':');
      final[_arr[0]] = _arr[1];
      return final;
    }, {});
    name = _valDescMap[data1.pv];
    color = _colorMap[name];
  }

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

  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',
        停止: '#666666',
        关: '#666666',
        开: '#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 };
