import Dom from '../../libs/dom'
import Widget from '../widget'
import util from '../../libs/util'
import _ from 'lodash'
import CountUp from 'countup.js'
const RadianPerDegree = Math.PI / 180

class Circle extends Widget {
  constructor(layer, screen) {
    super(layer, screen)
    this._contanier = Dom.createElement('div', 'circle-container comp', this.el)
    this.params = {}
    this.on('resize', () => {
      this.setPaint()
    })
  }

  setPaint() {
    let newPaint = this._mergePaint()
    if (this.originalData && this.originalData.length !== 0) {
      if (Number.isNaN(+newPaint.value)) {
        newPaint.value = this.originalData[0][newPaint.value] || 0
      }
      if (Number.isNaN(+newPaint.total)) {
        newPaint.total = this.originalData[0][newPaint.total] || 0
      }
    } else {
      newPaint.value = +newPaint.value || 20
      newPaint.total = +newPaint.total || 100
    }
    if (newPaint.total <= 0) {
      // 总数小于等于0
      console.warn('进度环：总数字段对应的值应为正数。')
    }
    let contanierWidth =
      this.layer.layout.width < this.layer.layout.height
        ? this.layer.layout.width
        : this.layer.layout.height
    let strokeWidth = (100 / contanierWidth) * newPaint.strokeWidth
    let radius = (100 - strokeWidth) / 2
    newPaint.startAngle = util.formatAngle(newPaint.startAngle) //角度归一化到0-360
    newPaint.endAngle = util.formatAngle(newPaint.endAngle) //角度归一化到0-360
    if (newPaint.startAngle === newPaint.endAngle) {
      newPaint.endAngle += 360
    }
    let startPosition = {
      x: 50 + radius * Math.sin(newPaint.startAngle * RadianPerDegree),
      y: 50 - radius * Math.cos(newPaint.startAngle * RadianPerDegree)
    }
    let endPosition = {
      x: 50 + radius * Math.sin(newPaint.endAngle * RadianPerDegree),
      y: 50 - radius * Math.cos(newPaint.endAngle * RadianPerDegree)
    }
    let pathAngle = 0
    if (newPaint.endAngle < newPaint.startAngle) {
      // 计算pathAngle，即路径扫过的角度，endAngle小于startAngle时应该为大弧，反之为小弧
      pathAngle = 360 - Math.abs(newPaint.endAngle - newPaint.startAngle)
    } else {
      pathAngle = Math.abs(newPaint.endAngle - newPaint.startAngle)
    }
    let midPosition = {
      // 计算中间点的位置，通过设置中间点将整个路径分成两段小弧，避免起始点一样时无法绘制整圆
      x:
        50 +
        radius *
          Math.sin((newPaint.endAngle - pathAngle / 2) * RadianPerDegree),
      y:
        50 -
        radius * Math.cos((newPaint.endAngle - pathAngle / 2) * RadianPerDegree)
    }
    let perimeter = pathAngle * RadianPerDegree * radius // 周长，path的总长
    let dashOffset = (1 - newPaint.value / newPaint.total) * perimeter // 进度条的长度
    let onlyValueChange = true
    let diffs = this._diff(newPaint, this.params)
    for (let i = 0; i < diffs.length; i++) {
      if (diffs[i] !== 'value' && diffs[i] !== 'total') {
        onlyValueChange = false
        break
      }
    }
    let svg = this._contanier.querySelector('svg')
    let path_d = `M 50,50 m ${startPosition.x - 50},${startPosition.y -
      50} a ${radius},${radius} 0 0 1 ${midPosition.x -
      startPosition.x},${midPosition.y -
      startPosition.y} a ${radius},${radius} 0 0 1 ${endPosition.x -
      midPosition.x},${endPosition.y - midPosition.y}`
    if (!svg || !onlyValueChange) {
      // 如果只有数值发生了改变，则进行局部刷新，不重新渲染整个图
      let gradients = ''
      let backgroundColor = newPaint.backgroundColor
      let color = newPaint.color
      if (Array.isArray(newPaint.backgroundColor)) {
        if (newPaint.backgroundColor.length > 1) {
          let gradient = util.gradient(
            'svg',
            newPaint.gradientDirection,
            ...newPaint.backgroundColor
          )
          gradients += gradient.gradient
          backgroundColor = `url(#${gradient.id})`
        } else {
          backgroundColor = newPaint.backgroundColor[0]
        }
      }
      if (Array.isArray(newPaint.color)) {
        if (newPaint.color.length > 1) {
          let gradient = util.gradient(
            'svg',
            newPaint.gradientDirection,
            ...newPaint.color
          )
          gradients += gradient.gradient
          color = `url(#${gradient.id})`
        } else {
          color = newPaint.color[0]
        }
      }
      let text = `
        <text x="50%" y="50%" dy=".3em" fill="${newPaint.labelColor}" text-anchor="middle" style="font-size: ${newPaint.labelSize}px">
          <tspan class="text"></tspan>%
        </text>`
      let svg = `
        <svg viewBox="0 0 100 100">
          <defs>${gradients}</defs>
          <path class="outer" 
            stroke="${backgroundColor}" 
            stroke-linecap="${newPaint.endShape}" 
            fill-opacity="0">
          </path>
          <path class="inner" 
            stroke-linecap="${newPaint.endShape}" 
            stroke="${color}" 
            fill-opacity="0" 
            style="stroke-dasharray: ${perimeter}px, ${perimeter}px; stroke-dashoffset: ${perimeter}px; transition: stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease 0s;">
          </path>
          ${newPaint.showLabel ? text : ''}
        </svg>`
      this._contanier.innerHTML = svg
    }
    let circle = this._contanier.querySelector('svg')
    let outerPath = this._contanier.querySelector('.outer')
    let innerPath = this._contanier.querySelector('.inner')
    Dom.css(circle, {
      width: contanierWidth + 'px',
      height: contanierWidth + 'px',
      margin: 'auto',
      display: 'block'
    })
    outerPath.setAttribute('d', path_d)
    innerPath.setAttribute('d', path_d)
    outerPath.setAttribute('stroke-width', strokeWidth)
    innerPath.setAttribute('stroke-width', strokeWidth)
    let text = this._contanier.querySelector('.text')
    if (text) {
      let options = {
        useEasing: true,
        useGrouping: true,
        separator: ''
      }
      let beforePercent = this.params.value / this.params.total
      let countup = new CountUp(
        text,
        beforePercent === Infinity || Number.isNaN(beforePercent)
          ? 0
          : beforePercent,
        (newPaint.value / newPaint.total) * 100,
        newPaint.decimalDigits,
        1,
        options
      )
      if (!countup.error) {
        countup.start()
      } else {
        console.error(countup.error)
      }
    }
    setTimeout(() => {
      Dom.css(innerPath, {
        strokeDashoffset: dashOffset + 'px'
      })
    }, 10)
    this.params = newPaint
  }

  _diff(newParams, oldParams) {
    let diffs = []
    for (let key in newParams) {
      if (!_.isEqual(oldParams[key], newParams[key])) {
        diffs.push(key)
      }
    }
    return diffs
  }
}

export default Circle
