import * as L from '@mapgis/leaflet'
import MapCoordSys from './MapCoordSys'
import { getMapRotateBounds } from '../support/utils'
const echarts = window.echarts
const EchartsLayerConstuct = L.Layer.extend({
  map: null, // 传入的leaflet地图
  chart: null,
  options: null,
  echartsInitOpts: null,
  canvas: null,
  initialize(map, options) {
    this.map = map
    this.options = options
    this.echartsInitOpts = options.echartsInitOpts
    this.layerId = options.layerId || 'echartlayerdefaultid'
    this.layerClass = options.classId || 'echartlayerdefaultclass'
    this.visible = true
    this.initDevicePixelRatio()
    this.initOptions(this.options)
    this.initEcharts()
    this._resizeCanvas()
  },
  initDevicePixelRatio() {
    this.devicePixelRatio = window.devicePixelRatio || 1
  },
  initOptions(options) {
    if (options) {
      if (options.leaflet) {
        return
      }
      this.options.leaflet = {
        roam: true
      }
    }
  },
  initEcharts() {
    echarts.registerCoordinateSystem('leaflet', MapCoordSys)
    echarts.extendComponentModel({
      type: 'leaflet',
      getBMap() {
        return this.__leaflet
      },
      defaultOption: {
        roam: false
      }
    })
    echarts.registerAction(
      {
        type: 'LeafletRoma',
        event: 'LeafletRoma',
        update: 'updateLayout'
      },
      function () {}
    )
  },
  _visible() {
    this.visible = true
    this.canvas.style.visibility = 'visible'
  },
  _unvisible() {
    this.visible = false
    this.canvas.style.visibility = 'hidden'
  },
  onAdd(map) {
    const vm = this
    this.map = map
    this.canvas = this._createCanvas()
    this.map.getPanes().overlayPane.appendChild(this.canvas)
    this.chart = echarts.init(this.canvas, null, this.echartsInitOpts)
    echarts.leafletMap = map
    const self = this
    map.on('resize', function (e) {
      self.resize()
    })
    map.on('zoomstart', function () {
      self._unvisible()
    })
    map.on('rotate', () => {
      self.resize()
    })
    echarts.extendComponentView({
      type: 'leaflet',
      render(mapModel, ecModel, api) {
        let rendering = true
        if (!self._echartRenderApi) {
          self._echartRenderApi = api
        }
        if (!self._mapModel) {
          self._mapModel = mapModel
        }
        const leafletMap = echarts.leafletMap
        const viewportRoot = api.getZr().painter.getViewportRoot()
        const coordSys = mapModel.coordinateSystem
        const moveHandler = function () {
          if (rendering || !vm.visible) {
            return
          }
          const topleft = leafletMap.getBounds().getNorthWest()
          const offset = leafletMap.latLngToLayerPoint(topleft)
          const mapOffset = [
            parseInt(offset.x, 10) || 0,
            parseInt(offset.y, 10) || 0
          ]
          viewportRoot.style.left = `${mapOffset[0]}px`
          viewportRoot.style.top = `${mapOffset[1]}px`
          coordSys.setMapOffset(mapOffset)
          mapModel.__mapOffset = mapOffset
          api.dispatchAction({
            type: 'LeafletRoma'
          })
        }
        const zoomEndHandler = function () {
          self._visible()
          if (rendering || !vm.visible) {
            return
          }
          api.dispatchAction({
            type: 'LeafletRoma'
          })
        }
        if (this._oldMoveHandler) {
          leafletMap.off('move', this._oldMoveHandler)
        }
        if (this._oldZoomEndHandler) {
          leafletMap.off('zoomend', this._oldZoomEndHandler)
        }
        leafletMap.on('move', moveHandler)
        leafletMap.on('zoomend', zoomEndHandler)
        this._oldMoveHandler = moveHandler
        this._oldZoomEndHandler = zoomEndHandler
        rendering = false
      }
    })
    this.chart.setOption(this.options)
  },
  onRemove() {
    this.chart.dispose()
  },
  _createCanvas() {
    const canvas = document.createElement('div')
    canvas.id = this.layerId
    canvas.style.top = '0px'
    canvas.style.left = '0px'
    canvas.height = `${this.map.getSize().y}px`
    canvas.width = `${this.map.getSize().x}px`
    canvas.style.height = `${this.map.getSize().y}px`
    canvas.style.width = `${this.map.getSize().x}px`
    canvas.style.zIndex = 1000
    canvas.setAttribute('id', this.layerId)
    canvas.setAttribute('class', this.layerClass)
    this.canvas = canvas
    return canvas
  },
  _resizeCanvas() {
    window.onresize = this.resize.bind(this)
  },
  _calcRotateBounds() {
    return getMapRotateBounds(this._map)
  },
  /**
   * 显示图层
   * @function L.zondy.EchartsLayer.prototype.show
   */
  show() {
    this._visible()
  },
  /**
   * 隐藏图层
   * @function L.zondy.EchartsLayer.prototype.hide
   */
  hide() {
    this._unvisible()
  },
  /**
   * 重置图层大小
   * @function L.zondy.EchartsLayer.prototype.resize
   */
  resize() {
    const self = this
    const size = self._calcRotateBounds().getSize()
    self.canvas.style.width = `${size.x}px`
    self.canvas.style.height = `${size.y}px`
    self.canvas.width = size.x
    self.canvas.height = size.y
    self.chart.resize()
    // 缓存echart api
    if (self._echartRenderApi && self._mapModel && self._map._rotate) {
      // 以下渲染逻辑和moveHandler一致
      const api = self._echartRenderApi
      const mapModel = self._mapModel
      const viewportRoot = api.getZr().painter.getViewportRoot()
      const coordSys = mapModel.coordinateSystem
      const topleft = this.map.getBounds().getNorthWest()
      const offset = this.map.latLngToLayerPoint(topleft)
      const mapOffset = [
        parseInt(offset.x, 10) || 0,
        parseInt(offset.y, 10) || 0
      ]
      viewportRoot.style.left = `${mapOffset[0]}px`
      viewportRoot.style.top = `${mapOffset[1]}px`
      coordSys.setMapOffset(mapOffset)
      mapModel.__mapOffset = mapOffset
      // 触发echarts图层更新
      api.dispatchAction({
        type: 'LeafletRoma'
      })
    }
  },
  /**
   * @function L.zondy.EchartsLayer.prototype.update
   * @param {*} option echarts.option
   * @see https://www.echartsjs.com/zh/tutorial.html#异步数据加载和更新
   * @description ECharts 由数据驱动,数据的改变驱动图表展现的改变,因此动态数据的实现也变得异常简单。所有数据的更新都通过 setOption实现,你只需要定时获取数据,setOption 填入数据,而不用考虑数据到底产生了那些变化,ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。
   */
  update(option) {
    this.chart.setOption(option)
  },
  /**
   * 删除图层
   * @function module:客户端可视化.EchartsLayer.prototype.remove
   */
  remove() {
    this.chart.clear()
    if (this.canvas.parentElement) {
      this.canvas.parentElement.removeChild(this.canvas)
    }
    this.map = undefined
    return this
  },
  setOpacity(opacity) {
    this.canvas.style.opacity = opacity
  }
})
const echartsLayer = function (echartsParams, options) {
  return new EchartsLayerConstuct(echartsParams, options)
}
export default echartsLayer