'use strict';
/**
 * an class to generate options for ECharts
 * @module option-generator
 * @see module:index
 */
const _ = require('lodash');
const numeral = require('numeral');
const util = require('../util/index');
const constant = require('../constant');
const { formatNumber } = require('../formatter');

// const MIN_DATA_ZOOM_LIMIT = 20;

const DEFAULT_OPTION = {
  animation: false,
  theme: constant.DEFAULT_THEME_NAME,
  tooltip: {},
  toolbox: {
    feature: {},
  },
  legend: {
    left: 0,
  },
  textStyle: {
    fontFamily: '"Helvetica Neue", "Microsoft YaHei"',
  },
};
const NAME_GAP = 52;

class OptionGenerator {
  constructor(extraOption) {
    const me = this;
    extraOption = extraOption || {};
    me._option = {};
    _.merge(me._option, DEFAULT_OPTION);
    _.merge(me._option, util.parseExtraOption(extraOption));
    this._configLayout();
    this.originalData = this._option.originalData || [];
  }

  configCoordinates(coordinates, horizontal, extraOption) {
    const me = this;
    const option = me._option;
    extraOption = extraOption || {};
    let dimensionAxis = 'xAxis';
    let measuresAxis = 'yAxis';
    if (horizontal) {
      const temp = measuresAxis;
      measuresAxis = dimensionAxis;
      dimensionAxis = temp;
    }
    this.measuresAxis = measuresAxis;
    this.dimensionAxis = dimensionAxis;
    option[dimensionAxis] = _.extend(option[dimensionAxis], {
      type: 'category',
      data: coordinates,
      axisLabel: {
        textStyle: {
          color: '#666',
        },
      },
    }, extraOption.category);

    if (extraOption.yAxis) {
      option[measuresAxis] = extraOption.yAxis;
    } else {
      option[measuresAxis] = [{
        type: 'value'
      }];
    }
    option[measuresAxis].forEach(item => {
      _.merge(item, {
        splitLine: {
          show: option[measuresAxis].length > 1 ? false : true,
          lineStyle: {
            color: '#f5f5f5',
          },
        },
        axisLine: {
          show: false
        },
        nameTextStyle: {
          color: '#999',
        },
        axisLabel: {
          textStyle: {
            color: '#666',
          },
        },
        nameLocation: 'middle', // start, middle, end
        nameGap: NAME_GAP,
      });
    });
    _.merge(option[measuresAxis][0], {
      name: option['data-yAxisName'] || ''
    });
    if (_.isNumber(option['data-yAxisMax'])) {
      option[measuresAxis][0].max = option['data-yAxisMax'];
    }
    if (_.isNumber(option['data-yAxisMin'])) {
      option[measuresAxis][0].min = option['data-yAxisMin'];
    }
    if (_.isNumber(option['data-yAxisMaxRight']) && option[measuresAxis][1]) {
      option[measuresAxis][1].max = option['data-yAxisMaxRight'];
    }
    if (_.isNumber(option['data-yAxisMinRight']) && option[measuresAxis][1]) {
      option[measuresAxis][1].min = option['data-yAxisMinRight'];
    }

    if (option['data-showDataZoomInside']) {
      option.dataZoom = [{
        show: true,
        type: 'slider',
        start: option['data-dataZoomInsideStart'] || 0,
        end: option['data-dataZoomInsideEnd'] || 100,
      }];
      this._configDataZoom();
    } else {
      option.xAxis.axisTick = { alignWithLabel: true };
    }
    return me;
  }

  configMeasures(type, measures, dataSet, extraSeriesOption) {
    const me = this;
    const option = me._option;
    option.series = [];
    _.each(measures, (measure) => {
      const colInfo = dataSet.colByName[measure];
      const data = this.originalData.map(v => {
        if (colInfo.format
          && colInfo.format.includes('dividedBy')
          && (!colInfo.format.includes('suffix') || colInfo.format.match(/dividedBy/g).length > 1)
        ) {
          // 数据必须修改的情况：分 -> 元 rate变更
          // 配合岛煮的format object化重新订正
          const result = /dividedBy\(([0-9.]+)\)/.exec(colInfo.format);
          if (result) {
            const factor = Number.parseFloat(result[1]);
            if (_.isNull(v[measure])) {
              return null;
            }
            return v[measure] / factor;
          }
        }
        return _.isNull(v[measure]) ? '-' : v[measure];
      });
      const formatData = this._getFormatData(dataSet, measure);
      // 为了在 recharts.js 中通过 JSON 伪序列化之后，可以通过 update 判断，添加一个数据字段
      // 因为 JSON.stringify(o) 会去除 function 字段
      option._formatData = formatData;
      // TODO: y轴格式化
      if (option[this.measuresAxis]) {
        if (!_.isArray(option[this.measuresAxis])) {
          option[this.measuresAxis] = [option[this.measuresAxis]]
        }
        option[this.measuresAxis] = option[this.measuresAxis].map((item, index) => (
          _.merge(item, {
            axisLabel: {
              formatter: v => {
                if (option['data-yAxisPercentageFormat'] && index === 0) {
                  // Y 轴特殊百分比
                  return numeral(v).format('0.00%');
                }
                if (option['data-yAxisPercentageFormatRight'] && index === 1) {
                  // Y 轴特殊百分比
                  return numeral(v).format('0.00%');
                }
                // const label = formatNumber(v, '0,0[.]0', '0[.]0[0]');
                // let suffix = '';
                // if (colInfo.format && _.includes(colInfo.format, 'suffix')) {
                //   // formatter添加后缀
                //   const result = /suffix\(&apos;(\S+)&apos;\)/.exec(colInfo.format);
                //   if (result) {
                //     suffix = result[1];
                //   }
                // }
                return formatNumber(v, '0,0[.]0', '0[.]0[0]');
              },
            },
          })
        ));
      }
      const yAxisIndex = (extraSeriesOption.measuresRight && (extraSeriesOption.measuresRight.indexOf(measure) > -1)) ? 1 : 0;
      const seriesType = _.isArray(type) ? type[yAxisIndex] : type;
      let position;
      switch (option['data-chartType']) {
        case 'lineBarMix':
          if (seriesType === 'line') {
            position = 'top';
          }
          if (seriesType === 'bar') {
            position = 'inside';
          }
          break;
        case 'line':
        case 'groupBar':
          position = 'top';
          break;
        case 'stackedBar':
          position = 'inside';
          break;
        case 'horizontalGroupBar':
          position = 'right';
          break;
        case 'horizontalStackedBar':
          position = 'inside';
          break;
        default:
          position = 'inside';
      }
      option.series.push(_.extend({
        name: colInfo.comments,
        type: seriesType,
        data,
        label: {
          normal: {
            show: option['data-showNormalLabel'] || false,
            position,
            formatter: option['data-showNormalLabel'] ? (
              ({ dataIndex }) => formatData[dataIndex]
            ) : null,
          }
        },
        areaStyle: {
          normal: {
            opacity: option['data-showAreaStyle'] ? 1 : 0
          }
        },
        yAxisIndex,
        smooth: option['data-smooth'] || false,
      }, extraSeriesOption));
      if (data.length === 1) {
        // 只有一条数据时，显示一个点
        option.series.forEach(item => {
          item.symbol = 'circle';
        });
      }
      if (option['data-hideSymbol']) {
        // 关闭圆点
        option.series.forEach(item => {
          item.symbol = 'image://';
        });
      }
    });
    option.tooltip.formatter = (measures => params => {
      /*
        {
          color,
          data/value,
          dataIndex,
          name,
          seriesName,
        }
       */
      if (!_.isArray(params)) {
        params = [params];
      }
      const content = params.map(param => {
        const displayName = param.seriesName;
        const measure = measures[param.seriesIndex];
        const formatData = this._getFormatData(dataSet, measure);
        // 针对 pie 类型的图表，需要显示百分比
        const percent = param.seriesType === 'pie' ? `(${param.percent}%)` : '';

        return `
          <div style="height:20px;">
            <span style="display:inline-block;border-radius:8px;width:8px;height:8px;background:${param.color};vertical-align:middle;"></span>
            <span style="display:inline-block;padding:0 5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;">${displayName}:</span>
            <span style="display:inline-block;vertical-align:middle;">${formatData[param.dataIndex] || '-'}</span>
            <span style="display:inline-block;vertical-align:middle;">${percent}</span>
          </div>
        `;
      });

      const name = params[0].name;
      return `
        <div style="padding:5px;border-radius:5px;font-size:12px;">
          <div style="font-size:14px;font-weight:700;">${name}</div>
          <div>
            ${content.join('')}
          </div>
        </div>
      `;
    })(measures);
    return me;
  }

  configLegend(colNames, dataSet) {
    const me = this;
    me._option.legend = me._option.legend ? me._option.legend : {};
    _.merge(me._option.legend, {
      data: _.map(colNames, colName => dataSet.colByName[colName].comments)
    });
    return me;
  }

  configLegendByData(data) {
    const me = this;
    me._option.legend = me._option.legend ? me._option.legend : {};
    _.merge(me._option.legend, {
      data,
    });
    return me;
  }

  toOption() {
    return this._option;
  }

  _getFormatData = (dataSet, measure) => {
    const data = this.originalData.map(v => v[measure]);
    const measureSchema = _.find(dataSet.schema, { name: measure });
    const formatData = measureSchema.format === 'auto' || _.isNull(measureSchema.format) ? data.map(v => formatNumber(v)) : dataSet.colValuesByName[measure];
    return formatData;
  }

  // _yFormatter = v => formatNumber(v, '0,0[.]0', '0')

  _configDataZoom() {
    // if (!_.isArray(this._option.dataZoom) || !this._option['data-showDataZoomInside']) {
    //   return;
    // }
    // else {
    //   this._option.dataZoom = _.map(this._option.dataZoom, opt => {
    //     let newOpt = _.assign({}, opt);
    //     if (opt.type !== 'inside') {
    //       // 由于dataZoom 会自适应grid，所以这里可以稍微根据自己的需要偏移
    //       // switch (this._option.padding) {
    //       //   case '':
    //       //     break;
    //       //   default:
    //       //     break;
    //       // }
    //     }
    //     return newOpt;
    //   });
    // }
  }

  _configLayout() {
    switch (this._option.padding) {
      case 'large':
        this._option.grid = {
          left: 100,
          right: 100,
          bottom: 30,
        };
        break;
      case 'small':
        this._option.grid = {
          left: 50,
          right: 50,
          bottom: 30,
          // containLabel: true,
        };
        break;
      case 'none':
        if (this._option['data-yAxisName']) {
          this._option.grid = {
            left: NAME_GAP + 12, // 52 + 12
            right: 30,
            bottom: 45,
          };
        } else {
          this._option.grid = {
            left: 10,
            // 露出最后一个刻度
            right: 30,
            bottom: 30,
            containLabel: true,
          };
        }
        break;
      default:
        break;
    }
    if (this._option.grid) {
      if (this._option.legend.show === false) {
        // 隐藏图例
        this._option.grid.top = 10;
      } else {
        this._option.grid.top = 60;
      }
    }
  }
}

module.exports = OptionGenerator;
