import Event from '../libs/event'
import util from '../libs/util'
import Source from '../source'
import _ from 'lodash'
import getDefaultProperties from '../constants/default_properties'
import cloneDeep from 'lodash/cloneDeep'
import { CountryLayer, ProvinceLayer, CityLayer } from '@cgcs2000/l7-district'
import renderPopup from '../libs/render_popup'

class Admin extends Event {
  constructor(layer, scene, zIndex) {
    super()
    this.id = layer.id
    this.type = layer.type
    this.name = layer.name
    this.layer = layer
    this._scene = scene
    this.rendered = false
    this.options = {
      zIndex
    }
    this.setSource()
    this.setStyle = _.debounce(this._setStyle, 1000)
  }

  /**
   * 根据source选项值获取组件的数据，并监听source.load事件，触发视图更新
   */
  setSource() {
    this.off('source.load')
    let source = this.layer.source
    if (!source || Object.keys(source).length === 0) {
      return
    }
    this.sourceInstance = new Source(this.layer.id, source, this)
    this.once('source.load', ({ data }) => {
      let source = this.layer.source
      if (source.parser) {
        let { adminArea, adminField } = source.parser
        let adminType = util.getAdminType(adminArea)
        Object.assign(this.options, {
          data,
          joinBy: [this._getJoinField(adminField, data), adminField],
          adcode: adminArea,
          depth: adminType + 1,
          autoFit: false
        })
      }
      this.setStyle()
    })
  }

  _setStyle() {
    console.log('setStyle')
    let { style } = this._mergeProperties()
    let { line, fill, bubble, label } = style
    this._getFillOption(fill)
    this._getLineOption(line)
    this._getBubbleOption(bubble)
    this._getLabelOption(label)
    this._getPopupOption()
    if (this.layerInstance) {
      // 移出原来的图层
      this.remove()
    }
    let depth = this.options.depth
    if (depth === 1) {
      this.layerInstance = new CountryLayer(this._scene, this.options)
    } else if (depth === 2) {
      this.layerInstance = new ProvinceLayer(this._scene, this.options)
    } else if (depth === 3) {
      this.layerInstance = new CityLayer(this._scene, this.options)
    }
  }

  _getLineOption(line) {
    Object.assign(this.options, {
      stroke: line.stroke,
      strokeWidth: line.strokeWidth
    })
  }

  _getFillOption(fill) {
    let { color, activeColor } = fill
    let fillOption = { activeColor }
    if (typeof color === 'string') {
      fillOption.color = color
    } else {
      let { field, type, stops } = color
      if (type === 'interval') {
        fillOption.color = {
          field: field,
          values: value => {
            let st = stops.find(stop => {
              let { min, max } = stop
              min = typeof min !== 'number' ? -Infinity : min
              max = typeof max !== 'number' ? Infinity : max
              return value >= min && value <= max
            })
            if (st) {
              return st.color
            } else {
              return '#000000'
            }
          }
        }
      } else {
        fillOption.color = {
          field: field,
          values: value => {
            let st = stops.find(stop => stop.value == value)
            if (st) {
              return st.color
            } else {
              return '#000000'
            }
          }
        }
      }
    }
    this.options.fill = fillOption
  }

  _getBubbleOption(bubble) {
    let { enable, size, color, shape, stroke, strokeWidth } = bubble
    let bubbleOption = {
      enable,
      shape,
      style: { stroke, strokeWidth }
    }
    if (typeof color === 'string') {
      bubbleOption.color = color
      bubbleOption.size = Array.isArray(size) ? size[0] : size
    } else {
      let { field, type, stops } = color
      if (type === 'interval') {
        bubbleOption.color = {
          field,
          values: value => {
            let st = stops.find(stop => {
              let { min, max } = stop
              min = typeof min !== 'number' ? -Infinity : min
              max = typeof max !== 'number' ? Infinity : max
              return value >= min && value <= max
            })
            if (st) {
              return st.color
            } else {
              return '#000000'
            }
          }
        }
        if (Array.isArray(size)) {
          let step = (size[1] - size[0]) / (stops.length - 1)
          bubbleOption.size = {
            field,
            values: value => {
              let stIndex = stops.findIndex(stop => {
                let { min, max } = stop
                min = typeof min !== 'number' ? -Infinity : min
                max = typeof max !== 'number' ? Infinity : max
                return value >= min && value <= max
              })
              if (stIndex !== -1) {
                return size[0] + step * stIndex
              } else {
                return 4
              }
            }
          }
        } else {
          bubbleOption.size = size
        }
      } else {
        bubbleOption.color = {
          field,
          values: value => {
            let st = stops.find(stop => stop.value == value)
            if (st) {
              return st.color
            } else {
              return '#000000'
            }
          }
        }
        if (Array.isArray(size)) {
          let step = (size[1] - size[0]) / (stop.length - 1)
          bubbleOption.size = {
            field,
            values: value => {
              let stIndex = stops.findIndex(stop => stop.value == value)
              if (stIndex !== -1) {
                return size[0] + step * stIndex
              } else {
                return 4
              }
            }
          }
        } else {
          bubbleOption.size = size
        }
      }
    }
    this.options.bubble = bubbleOption
  }

  _getLabelOption(label) {
    this.options.label = cloneDeep(label)
  }

  _getPopupOption() {
    this.options.popup = {
      enable: true,
      openTriggerEvent: 'click',
      Html: properties => renderPopup(properties)
    }
  }
  remove() {
    this.layerInstance.destroy()
    this.layerInstance = null
  }

  show() {
    this.layerInstance.show()
  }

  hide() {
    this.layerInstance.hide()
  }

  fitBounds() {
    this.layerInstance.fitBounds({
      padding: 100
    })
  }

  setIndex(index) {
    this.options.zIndex = index
    this.setStyle()
  }

  _mergeProperties() {
    let defaultProperties = getDefaultProperties(this.type)
    let { style, action } = this.layer
    let newProperties = util.mergeObjs(cloneDeep(defaultProperties), {
      style: style || {},
      action: action || {}
    })
    return newProperties
  }

  _getJoinField(field, data) {
    if (!data.length) {
      return 'adcode'
    }
    return Number.isNaN(Number(data[0][field])) ? 'NAME_CHN' : 'adcode'
  }
}

export default Admin
