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

/**
 * data 图数据 例如：[{ date: '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 }
 * titleConfig: { title: '', fontSize: '16px', fontWeight: '700', color: '#fff' }  图的标题
 * titleYConfig: { title: '', fontSize: '10px', fontWeight: 'bold', color: '#000' }  Y轴标题
 * formatFunX 格式化x函数
 * formatFunY 格式化y函数
 * barColors 柱形颜色 例如：['#98abc5', '#7b6888']
 * legendConfig: { fontSize: '10px', fontWeight: '500', color: '#000', r: 0} 图例
 * lineConfig 背景线及坐标轴配置
 * clickback 点击回调函数
 * tipFun 自定义提示回调函数
 * barValConfig 柱上字体配置
 * formatBarVal 柱上内容格式化函数
 */
const D3GroupedBarChart = (params) => {
  const defaultConfig = {
    margin: { top: 80, right: 80, bottom: 30, left: 60 },
    titleConfig: { title: '', fontSize: '16px', fontWeight: '700', color: '#fff' },
    titleYConfig: { title: '', fontSize: '10px', fontWeight: 'bold', color: '#000' },
    barColors: ['#98abc5', '#8a89a6', '#7b6888', '#6b486b', '#a05d56', '#d0743c', '#ff8c00'],
    legendConfig: { show: true, fontSize: '10px', fontWeight: '500', color: '#000', r: 0},
    lineConfig: {
      colorX: '', typeX: 'solid', xColor: '#333', labelColorX: '#555',
      colorY: '', typeY: 'solid', yColor: '#333', labelColorY: '#555',
    },
    barValConfig: { show: true, fontSize: '14px', fontWeight: '500', color: 'orange' }
  }
  const {
    data,
    names,
    id,
    height,
    margin,
    titleConfig,
    titleYConfig,
    formatFunX,
    formatFunY,
    barColors,
    legendConfig,
    lineConfig,
    clickback,
    tipFun,
    barValConfig,
    formatBarVal
  } = params;
  const container = document.getElementById(`${id}`);
  if (!container) return;
  // 获取 div 标签下的所有子节点
  var pObjs = container.childNodes;
  for (var i = pObjs.length - 1; i >= 0; i--) {
    container.removeChild(pObjs[i]);
  }
  if(!data.length) 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;

  const _barColors = isArray(barColors) && barColors.length ? barColors : defaultConfig.barColors;
  const _titleConfig = setNewValue(titleConfig, defaultConfig.titleConfig);
  const _titleYConfig = setNewValue(titleYConfig, defaultConfig.titleYConfig);
  const _legendConfig = setNewValue(legendConfig, defaultConfig.legendConfig);
  const _lineConfig = setNewValue(lineConfig, defaultConfig.lineConfig);
  const _barValConfig = setNewValue(barValConfig, defaultConfig.barValConfig);

  // 用于绘制每条柱
  const barWidth = (_width / data.length) * 0.9;

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

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

  let x1 = d3.scaleBand().padding(0.05);

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

  let z = d3.scaleOrdinal().range(_barColors);

  let keys = Object.keys(names);

  let tip = d3Tip.default() // 设置tip
    .attr('class', 'd3-tip')
    .offset([-10, 0])
    .html(function (d) {
      const currentData = d.target.__data__;
      const tipStr = isFun(tipFun) ? tipFun(currentData) : (
        '<strong>' +names[currentData.key] +"<br>" + _titleYConfig.title + ":</strong> <span>" +currentData.value+ '</span>'
      );
      return tipStr;
    });

  svg.call(tip);
  x0.domain((function(){
    let t = []
    data.map(function (d, i) {
      t.push(i)
    })
    return t
  })());
  x1.domain(keys).rangeRound([0, x0.bandwidth()]);
  y.domain([ 0, d3.max(data, function (d) {
    return d3.max(keys, function (key) {
      return isFun(formatFunY) ? formatFunY(d[key]) : d[key];
    })
  })]).nice();

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

  g.append('g') // 画x轴
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + _height + ')')
    .call(d3.axisBottom(x0).tickFormat(function(d){
      return isFun(formatFunX) ? formatFunX(data[d].date) : data[d].date
    }))
  if(_lineConfig.xColor) {
    g.selectAll('.axis--x path')
      .attr('stroke', _lineConfig.xColor)
    g.selectAll('.axis--x .tick line')
      .attr('stroke', _lineConfig.xColor)
  }
  if(_lineConfig.labelColorX) {
    g.selectAll('.axis--x .tick text')
      .attr('fill', _lineConfig.labelColorX)
  }
  if(_lineConfig.colorY) {
    let lineY = g.selectAll('.axis--x .tick') 
      .append('line')
      .attr('class', 'bg-line')
      .attr('stroke', function(d, i) {
        return _lineConfig.colorY
      })
      .attr('y2', -_height);
    // 实线
    if(_lineConfig.typeY === 'solid') {
      lineY.attr('shape-rendering', 'crispEdges')
    }
    // 虚线
    if(_lineConfig.typeY === 'dashed') {
      lineY.style("stroke-dasharray", "5,5")
    }
  }

  g.append('g') // 画y轴
    .attr('class', 'axis axis--y')
    .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', _titleYConfig.color)
    .attr('font-size', _titleYConfig.fontSize)
    .attr('font-weight', _titleYConfig.fontWeight)
    .attr('text-anchor', 'start')
    .text(_titleYConfig.title);
  if(_lineConfig.yColor) {
    g.selectAll('.axis--y path')
      .attr('stroke', _lineConfig.yColor)
    g.selectAll('.axis--y .tick line')
      .attr('stroke', _lineConfig.yColor)
  }
  if(_lineConfig.labelColorY) {
    g.selectAll('.axis--y .tick text')
      .attr('fill', _lineConfig.labelColorY)
  }
  if(_lineConfig.colorX || _lineConfig.xColor) {
    let lineY = g.selectAll('.axis--y .tick') 
      .append('line')
      .attr('class', 'bg-line')
      .attr('stroke', function(d, i) {
        if(i) {
          return _lineConfig.colorX || '#fff'
        }else{
          return _lineConfig.xColor
        }
      })
      .attr('x2', _width);
    // 实线
    if(_lineConfig.typeX === 'solid') {
      lineY.attr('shape-rendering', 'crispEdges')
    }
    // 虚线
    if(_lineConfig.typeX === 'dashed') {
      lineY.style("stroke-dasharray", function(d, i) {
        if(!_lineConfig.colorX && _lineConfig.xColor && !i) {
          return "0,0"
        }
        return "5,5"
      })
    }
  }
  // 画柱状图
  let gBar = g.append('g') 
    .selectAll('g')
    .data(data)
    .enter()
    .append('g')
    .attr('class', 'item-rect')
    .attr('transform', function (d, i) {
      return 'translate(' + x0(i) + ',0)'
    })
    
  gBar.selectAll('rect')
    .data(function (d) {
      return keys.map(function (key) {
        return { key: key, value: d[key] || 0, initData: d }
      })
    }) // 把json数据转格式
    .enter()
    .append('rect')
    .on('mouseover', tip.show)
    .on('mouseout', tip.hide)
    .on('click', function (d, i) {
      tip.hide()
      if(isFun(clickback)) {
        clickback(d.target.__data__)
      }
    })
    .attr('x', function (d) {
      return x1(d.key)
    })
    .attr('cursor', 'pointer')
    .attr('width', x1.bandwidth())
    .attr('fill', function (d) {
      return d.initData && d.initData.initConfig && d.initData.initConfig.barColor ? d.initData.initConfig.barColor : z(d.key)
    })
    .attr('height', 0)
    .attr('y', _height)
    .transition()
    .duration(750)
    .delay(function (d, i) {
      return i * 10
    })
    .attr('y', function (d) {
      return y(d.value) ? y(d.value) : 0;
    })
    .attr('height', function (d) {
      return y(d.value) ? _height - y(d.value) : _height;
    })
  if(_barValConfig.show) {
    gBar.selectAll('text')
      .data(function (d) {
        return keys.map(function (key) {
          return { key: key, value: d[key] || 0, initData: d }
        })
      }) // 把json数据转格式
      .enter()
      .append('text')
      .attr('fill', function(d) {
        return d.initData && d.initData.initConfig && d.initData.initConfig.barColor ? d.initData.initConfig.barColor : (_barValConfig.color ? _barValConfig.color : z(d.key))
      })
      .attr('font-size', _barValConfig.fontSize)
      .attr('font-weight', _barValConfig.fontWeight)
      .attr('text-anchor', 'middle')
      .attr('x', function(d, i) {
        return x1(d.key);
      })
      .attr('y', function(d) {
        return y(d.value) ? y(d.value) : 0;
      })
      .attr('dx', barWidth / 2)
      .attr('dy', '-1em')
      .text(function(d) {
        return isFun(formatBarVal) ? formatBarVal(d.value) : d.value
      })
  }

  if(_legendConfig.show) {
    let legend = g.append('g') // 画legend
      .attr('font-family', 'sans-serif')
      .attr('font-size', _legendConfig.fontSize)
      .attr('font-weight', _legendConfig.fontWeight)
      .attr('fill', _legendConfig.color)
      .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 + ')'
      });
    if(!_legendConfig.r) {
      legend.append('rect')
        .attr('x', _width - 19)
        .attr('width', 19)
        .attr('height', 19)
        .attr('fill', z);
    }else{
      legend.append('circle')
        .attr('cx', _width - 18 + _legendConfig.r)
        .attr('cy', 9.5)
        .attr('r', _legendConfig.r)
        .attr('fill', z);
    }

    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', _titleConfig.fontSize)
    .attr('font-weight', _titleConfig.fontWeight)
    .attr('text-anchor', 'middle')
    .attr('x', width / 2)
    .attr('y', 20)
    .text(_titleConfig.title); 
}

export default D3GroupedBarChart;
