    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