import * as L from '@mapgis/leaflet'
import { FeatureRender, GeometryType } from '@mapgis/webclient-common'
import {
  convertFeature,
  createGraphic,
  updatePolylineMarkers,
  updateMultiPolylineMarkers,
  getAreaCoords
} from './convertFeatureToLeafletGraphicUtil'
import ConvertGeometryUtil from './ConvertGeometryUtil'
import ConvertSymbolUtil from './ConvertSymbolUtil'
import LeafletPlugin from './LeafletPlugin'
const toLeafletStyle = ConvertSymbolUtil.convertSymboltoLeafletStyle
class LeafletFeatureRender extends FeatureRender {
  /**
   * @description: 绘制要素
   * @param {*} innerLayer
   * @param {*} features
   * @return {*}
   */
  drawFeature(innerLayer, features) {
    if (innerLayer) {
      const { layerVisible, layerOpacity } = innerLayer
      features.forEach((feature) => {
        if (feature.visible) {
          // 异步添加
          const graphic = convertFeature(feature)
          // 绑定id,leaflet内部处理了id方式,为保持逻辑一致
          graphic['commonFeatureId'] = feature.id
          // 设置图层id
          graphic['commonLayerId'] = innerLayer.commonLayerId
          // 设置图层透明度和显隐
          LeafletPlugin.setGraphicVisibleOpacity(
            graphic,
            layerOpacity,
            layerVisible
          )
          innerLayer.addLayer(graphic)
        }
      })
    }
  }
  /**
   * @description: 更新样式
   * @param {Object} innerLayer
   * @param {Array<Feature>} features
   * @param {Array<Object>} updateDetail 要素更新细节
   * @return {*}
   */
  updateFeature(innerLayer, features, updateDetail) {
    if (innerLayer) {
      super.updateFeature(innerLayer, features, updateDetail)
      features.forEach((feature, i) => {
        const detail = updateDetail[i]
        if (!detail || !feature) return
        this._update(
          innerLayer,
          detail.symbolUpdated,
          detail.geometryUpdated,
          feature
        )
      })
    }
  }
  /**
   * @description: 更新几何
   * @param {*} innerLayer
   * @param {*} geometryUpdated
   * @param {*} feature
   * @return {*}
   */
  _update(innerLayer, symbolUpdated, geometryUpdated, feature) {
    const geometry = feature.geometry
    const symbol = feature.symbol
    const isGeometryUpdate = !!geometryUpdated
    const isSymbolUpdate = !!symbolUpdated
    let isRedraw = false
    const graphic = this._getGraphicByFeatureId(innerLayer, feature.id)
    // 处理要素刷新机制
    const visible = feature.visible
    if (!visible) {
      this.clearFeature(innerLayer, [feature])
      return
    }
    // 几何图形
    if (!graphic) {
      this.drawFeature(innerLayer, [feature])
      return
    }
    // 处理切换符号的机制
    if (symbolUpdated) {
      const { key, oldValue, value } = symbolUpdated
      if (oldValue && value && oldValue.type !== value.type) {
        isRedraw = true
      }
      if (key === 'type') {
        isRedraw = true
      }
    }
    if (!isRedraw) {
      switch (geometry.type) {
        case GeometryType.point: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol) || {}
            graphic.setStyle(leafletStyle)
          }
          if (isGeometryUpdate) {
            const latlngs = ConvertGeometryUtil.toLeafletCoords(geometry)
            graphic.setLatLng(latlngs[0])
          }
          break
        }
        case GeometryType.multiPoint: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            graphic.eachLayer((layer) => {
              layer.setStyle(leafletStyle)
            })
          }
          if (isGeometryUpdate) {
            const latlngs = ConvertGeometryUtil.toLeafletCoords(geometry)
            const keys = Object.keys(graphic._layers)
            const layers = keys.map((key) => graphic._layers[key]) || []
            const latlngsNum = latlngs.length
            let len = layers.length
            // 更新多点
            if (len !== latlngsNum) {
              if (len > latlngsNum) {
                while (len !== latlngsNum) {
                  graphic.removeLayer(layers[len - 1])
                  len -= 1
                }
                let i = 0
                graphic.eachLayer((layer) => {
                  layer.setLatLng(latlngs[i])
                  i += 1
                })
              } else {
                const symbolType = feature.symbol.type
                const style = toLeafletStyle(feature.symbol)
                latlngs.forEach((latlng, i) => {
                  if (i < len) {
                    layers[i].setLatLng(latlng)
                  } else {
                    const marker = createGraphic(symbolType, latlng, style)
                    graphic.addLayer(marker)
                  }
                })
              }
            } else {
              let i = 0
              graphic.eachLayer((layer) => {
                layer.setLatLng(latlngs[i])
                i += 1
              })
            }
          }
          break
        }
        case GeometryType.lineString: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            if (graphic['__line__graphic']) {
              graphic['__line__graphic'].setStyle(leafletStyle)
            }
          }
          if (isGeometryUpdate) {
            const latlngs = ConvertGeometryUtil.toLeafletCoords(geometry)
            if (graphic['__line__graphic']) {
              graphic['__line__graphic'].setLatLngs(latlngs)
            }
          }
          if (symbol.marker) {
            updatePolylineMarkers(feature, graphic)
          }
          break
        }
        case GeometryType.multiLineString: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            if (graphic['__line__graphic']) {
              graphic['__line__graphic'].setStyle(leafletStyle)
            }
          }
          if (isGeometryUpdate) {
            const latlngs = ConvertGeometryUtil.toLeafletCoords(geometry)
            if (graphic['__line__graphic']) {
              graphic['__line__graphic'].setLatLngs(latlngs)
            }
          }
          if (symbol.marker) {
            updateMultiPolylineMarkers(feature, graphic)
          }
          break
        }
        case GeometryType.multiPolygon:
        case GeometryType.polygon: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            graphic.setStyle(leafletStyle)
          }
          if (isGeometryUpdate) {
            const latlngs = getAreaCoords(symbol.type, geometry, feature)
            if (graphic.setLatLngs) {
              graphic.setLatLngs(latlngs)
            } else if (graphic.setLatLng) {
              graphic.setLatLng(latlngs)
            }
          }
          break
        }
        case GeometryType.extent: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            graphic.setStyle(leafletStyle)
          }
          if (isGeometryUpdate) {
            const latlngs = getAreaCoords(symbol.type, geometry, feature)
            if (graphic instanceof L.Rectangle) {
              graphic.setBounds(L.latLngBounds(latlngs[0], latlngs[1]))
            } else if (graphic.setLatLngs) {
              graphic.setLatLngs(latlngs)
            } else if (graphic.setLatLng) {
              graphic.setLatLng(latlngs)
            }
          }
          break
        }
        case GeometryType.circle: {
          if (isSymbolUpdate) {
            const leafletStyle = toLeafletStyle(feature.symbol)
            graphic.setStyle(leafletStyle)
          }
          if (isGeometryUpdate) {
            const latlngs = getAreaCoords(
              symbol.type,
              geometry.toPolygon(),
              feature
            )
            if (graphic.setLatLngs) {
              graphic.setLatLngs(latlngs)
            } else if (graphic.setLatLng) {
              graphic.setLatLng(latlngs)
            }
          }
          break
        }
        default: {
          break
        }
      }
    }
    // 重新绘制
    if (isRedraw) {
      this._redrawFeature(innerLayer, feature)
    }
  }
  /**
   * @description: 清除要素
   * @param {*} innerLayer
   * @param {*} features
   * @return {*}
   */
  clearFeature(innerLayer, features) {
    if (innerLayer) {
      super.clearFeature(innerLayer, features)
      features.forEach((feature) => {
        const _graphic = this._getGraphicByFeatureId(innerLayer, feature.id)
        if (_graphic) {
          innerLayer.removeLayer(_graphic)
        }
      })
    }
  }
  /**
   * @description: 清空上下文图层
   * @param {*} innerLayer
   * @return {*}
   */
  clear(innerLayer) {
    if (innerLayer) {
      super.clear(innerLayer)
      innerLayer.clearLayers()
    }
  }
  /**
   * @description: 根据要素id获取引擎图元对象
   * @param {String} featureId
   * @return {Object}
   */
  _getGraphicByFeatureId(innerLayer, featureId) {
    let _graphic = null
    if (innerLayer && featureId) {
      innerLayer.eachLayer((graphic) => {
        if (graphic['commonFeatureId'] === featureId) {
          _graphic = graphic
          return _graphic
        }
      })
    }
    return _graphic
  }
  _redrawFeature(innerLayer, feature) {
    // 类型不一致,重绘
    this.clearFeature(innerLayer, [feature])
    this.drawFeature(innerLayer, [feature])
  }
}
export default LeafletFeatureRender