import moment from 'moment';
import _ from 'lodash';

/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const axisWidth = 40;

/**
 * 图表系列名称格式化
 *
 * @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;
  const formatStr = contrastOption === 'day' ? '2020-01-01 HH:mm:00' : '2020-01-DD HH:mm:00';
  return dataModel.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) => {
  // 只有一个数据曲线时显示markline
  if (!dataItem || dataSource.length !== 1) return {};
  const data = [];
  data.push({ type: 'min', name: '最小值', label: { color: '#FFFFFF' } });
  data.push({ type: 'max', name: '最大值', label: { color: '#FFFFFF' } });
  return {
    symbol: 'pin',
    data,
  };
};

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

/**
 * 图表配置项生成
 *
 * @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) => {
  const needUnit = _.get(config, 'needUnit', false);
  const curveCenter = _.get(config, 'curveCenter', false);
  const nameWithSensor = _.get(config, 'nameWithSensor', true);
  const showGridLine = _.get(config, 'showGridLine', false);
  const showMarkLine = _.get(config, 'showMarkLine', false);
  const showPoint = _.get(config, 'showPoint', false);
  const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []);

  // 自定义属性
  const restOption = _.pick(cusOption, ['title', 'legend']);

  // 一种指标一个y轴
  const yAxisMap = new Map();
  dataSource.forEach((item, index) => {
    const { sensorName, unit } = item;
    const key = sensorName;

    if (!yAxisMap.has(key)) {
      const i = yAxisMap.size;
      const axis = {
        type: 'value',
        name: needUnit ? unit : null,
        position: i % 2 === 0 ? 'left' : 'right',
        offset: Math.floor(i / 2) * axisWidth,
        axisLabel: {
          formatter: (value) => (value > 100000 ? `${value / 1000}k` : value),
        },
        axisLine: {
          show: true,
        },
        nameTextStyle: {
          align: i % 2 === 0 ? 'right' : 'left',
        },
        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 ? [...yAxisMap.values()] : { type: 'value' };

  // 根据y轴个数调整边距
  const leftNum = Math.ceil(yAxisMap.size / 2);
  const rightNum = Math.floor(yAxisMap.size / 2);
  const grid = {
    top: needUnit ? 80 : 60,
    left: 10 + leftNum * axisWidth,
    right: rightNum === 0 ? 20 : rightNum * axisWidth,
  };

  // 根据"指标名称"分类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 };
  })();

  const series = dataSource.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 yAxisIndex = yAxisInterator.get(sensorName);
    const markLine = showMarkLine ? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes) : {};
    const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {};
    return {
      notMerge: true,
      name,
      type,
      data,
      areaStyle,
      yAxisIndex,
      smooth,
      unit,
      markLine,
      markPoint,
    };
  });

  // 由于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),
  );
  const xAxis = { type: 'time', min, max };
  decorateAxisGridLine(xAxis, showGridLine);

  const tooltipTimeFormat = !contrast
    ? 'YYYY-MM-DD HH:mm:ss'
    : contrastOption === 'day'
    ? 'HH:mm'
    : 'DD HH:mm';
  const tooltip = {
    timeFormat: tooltipTimeFormat,
    // trigger: 'axis',
    // axisPointer: {
    //   type: 'cross'
    // }
  };

  return {
    yAxis,
    grid,
    xAxis,
    series,
    tooltip,
    ...restOption,
  };
};

export default optionGenerator;
