import * as d3 from 'd3';
import * as d3Tip from 'd3-tip';
import { isFun, isArray, setNewValue } from '../../../utils/util.js';

/**
 * data 图数据 例如：[{ label: '2011', q1: 155, q2: 200, q3: 214, q4: 234 }]
 * names 数据字段对应说明 例如：{ q1: '第一季度', q2: '第二季度', q3: '第三季度', q4: '第四季度' }
 * id 图id
 * height 图高 例如：500
 * margin 例如：{ top: 80, right: 80, bottom: 30, left: 60 }
 * title  图的标题 例如：XX公司近几年各季度产生利润情况汇总
 * titleY  Y轴标题 例如：利润(万)
 * formatFunX 格式化x函数
 * formatFunY 格式化y函数
 * barColors 柱形颜色 例如：['#98abc5', '#7b6888', '#a05d56', '#ff8c00']
 */
const D3StackedBarChart = (params) => {
  const defaultConfig = {
    margin: { top: 80, right: 80, bottom: 30, left: 60 },
    titleConfig: { title: '', fontSize: '14px', fontWeight: '700', color: '#000' }
  }
  const {
    data,
    names,
    id,
    height,
    margin,
    title,
    titleY,
    formatFunX,
    formatFunY,
    barColors
  } = params;
  const container = document.getElementById(`${id}`);
  if (!container) return;

  const width = container.offsetWidth;
  const _margin = setNewValue(margin, defaultConfig.margin);

  const _width = width - _margin.left - _margin.right;
  const _height = height - _margin.top - _margin.bottom;

  // 设置总宽高
  let svg = d3.select(`#${id}`)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  let x = d3.scaleBand()
    .rangeRound([0, _width])
    .paddingInner(0.1);

  let y = d3.scaleLinear().rangeRound([_height, 0]);

  let z = d3.scaleOrdinal().range(isArray(barColors) && barColors.length ? barColors : d3.schemeCategory10);

  let keys = Object.keys(names);

  let series = d3
    .stack()
    .keys(keys)
    .offset(d3.stackOffsetDiverging)(data)

  let tip = d3Tip.default() // 设置tip
    .attr('class', 'd3-tip stacked-demo')
    .offset([-10, 0])
    .html(function (d) {
      const currentData = d.target.__data__;
      let total = 0;
      const labelX = isFun(formatFunX) ? formatFunX(currentData.data.label) : currentData.data.label;
      let items = '<strong>' +labelX+'</strong><br>';
      for(let index = 0; index < keys.length; index++) {
        const item = keys[index];
        const itemColor =  z(item);
        const label = names[item];
        const value = isFun(formatFunY) ? formatFunY(currentData.data[item]) : currentData.data[item];
        items += '<span style="color:' + itemColor + '">' + label + ': ' + value + '</span><br>';
        total += currentData.data[item];
      }
      total = isFun(formatFunY) ? formatFunY(total) : total;
      items += '<span style="color:#fff">汇总: ' + total + '</span>';
      return items;
    })

  svg.call(tip);

  x.domain(
    data.map(function (d) {
      return d.label;
    })
  );
  y.domain([
    d3.min(series, function (serie) {
      return d3.min(serie, function (d) {
        return d[0]
      })
    }),
    d3.max(series, function (serie) {
      return d3.max(serie, function (d) {
        return d[1]
      })
    })
  ])

  let g = svg.append('g')
    .attr('transform', 'translate(' + _margin.left + ',' + _margin.top + ')'); // 设最外包层在总图上的相对位置

  g.append('g') // 画柱状图
    .selectAll('g')
    .data(series)
    .enter()
    .append('g')
    .attr('fill', function (d) {
      return z(d.key);
    })
    .selectAll('rect')
    .data(function (d) {
      return d
    })
    .enter()
    .append('rect')
    .on('mouseover', tip.show)
    .on('mouseout', tip.hide)
    .attr('width', x.bandwidth)
    .attr('cursor', 'pointer')
    .attr('x', function (d) {
      return x(d.data.label);
    })
    .attr('height', 0)
    .attr('y', y(0))
    .transition()
    .duration(750)
    .delay(function (d, i) {
      return i * 10
    })
    .attr('y', function (d) {
      return y(d[1])
    })
    .attr('height', function (d) {
      return y(d[0]) - y(d[1])
    })

  g.append('g') // 画x轴
    .attr('class', 'axis')
    .attr('transform', 'translate(0,' + y(0) + ')')
    .call(d3.axisBottom(x))

  g.append('g') // 画y轴
    .attr('class', 'axis')
    .call(d3.axisLeft(y).ticks(null, 's'))
    .append('text')
    .attr('x', 2)
    .attr('y', y(y.ticks().pop()) + 0.5)
    .attr('dy', '0.32em')
    .attr('fill', '#000')
    .attr('font-weight', 'bold')
    .attr('text-anchor', 'start')
    .text(titleY)

  let legend = g
    .append('g') // 画legend
    .attr('font-family', 'sans-serif')
    .attr('font-size', 10)
    .attr('transform', 'translate(65,0)')
    .attr('text-anchor', 'end')
    .selectAll('g')
    .data(keys.slice())
    .enter()
    .append('g')
    .attr('transform', function (d, i) {
      return 'translate(0,' + i * 20 + ')'
    });

  legend.append('rect')
    .attr('x', _width - 19)
    .attr('width', 19)
    .attr('height', 19)
    .attr('fill', function (d) {
      return z(d);
    });

  legend.append('text')
    .attr('x', _width - 24)
    .attr('y', 9.5)
    .attr('dy', '0.32em')
    .text(function (d) {
      return names[d]
    });

  svg.append('g') // 输出标题
    .attr('class', 'grouped-bar--title')
    .append('text')
    .attr('fill', '#000')
    .attr('font-size', '16px')
    .attr('font-weight', '700')
    .attr('text-anchor', 'middle')
    .attr('x', width / 2)
    .attr('y', 20)
    .text(title);
}

export default D3StackedBarChart;
