import Style from 'ol/style/Style'
import Photo from 'ol-ext/style/Photo'
import { newPoint } from '@/utils/map.js'
import VectorLayer from 'ol/layer/Vector.js'
import { Cluster, Vector as VectorSource } from 'ol/source.js'
import { Vector } from 'ol/layer.js'
import * as KMap from '@/utils/ol-map/KMap.js'
import { Fill, Text, Icon, Stroke } from 'ol/style.js'
// import eventBus from '@/api/eventBus.js'
import { extractCoordinates } from '@/common/commonFun.js'

import treeImg from '@/assets/img/map/tree.png'
import treeActiveImg from '@/assets/img/map/tree-active.png'
import activeBgImg from '@/assets/img/map/active-bg.png'
import hereImg from '@/assets/img/map/here.png'
import progressImg from '@/assets/img/map/progress.png'
import progressActiveImg from '@/assets/img/map/progress-active.png'

/**
 * 果树聚合点位图层
 */
class ClusterPointsLayer {
  constructor(kmap) {
    const that = this
    this.cloudFilenameCache = {}
    this.statusTitleStyleCache = {}
    this.textBgStyleCache = {}
    this.bgStyleCache = {}
    this.activeBgStyleCache = {}
    this.progressBgStyleCache = {}
    this.enterSelectTree = false
    this.selectableActiveTree = null
    that.initLayer(kmap)
    that.kmap = kmap

    // that.addMapSingerClick()

    this.currentPoint = null
  }

  addMapSingerClick() {
    const that = this
    that.kmap.on('singleclick', (evt) => {
      that.kmap.map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
        if (layer instanceof VectorLayer && layer.get('name') === 'clusterPointsLayer') {
          const fs = that.selectFeature(feature)
          // if (that.selectableActiveTree) {
          //   that.selectableActiveTree.set('selectableActive', false)
          // }
          // if (that.enterSelectTree) {
          //   // eventBus.emit('showTreePopup', fs.get('sampleId'))
          //   that.selectableActiveTree = fs
          //   fs.set('selectableActive', true)
          //   return
          // }
          // const miniUserId = fs.get('miniUserId') && !fs.get('virtual')
          // const isMy = fs.get('my')
          // if (isMy) {
          //   localStorage.setItem('showMapText', true)
          // } else if (miniUserId) {
          //   // eventBus.emit('adoptMap:friendTree', {
          //   //   sampleId: fs.get('sampleId'),
          //   // })
          // } else {
          //   // eventBus.emit('showTreePopup', fs.get('sampleId'))
          //   that.selectableActiveTree = fs
          //   fs.set('selectableActive', true)
          // }
        }
      })
    })
  }

  initLayer(kmap) {
    const that = this
    this.vectorStyle = new KMap.VectorStyle()
    this.clusterSource = new VectorSource({})
    this.clusterLayer = new Vector({
      source: new Cluster({
        distance: 40,
        source: this.clusterSource,
      }),
      className: 'ol-layer-cluster',
      name: 'clusterPointsLayer',
      minZoom: 14.6,
      maxZoom: 22,
      zIndex: 1001,
      style: function (feature) {
        const f = that.selectFeature(feature)
        const isVisible = f.get('visible') !== false
        const selectableActive = f.get('selectableActive')
        if (!isVisible) {
          return []
        }
        if (that.enterSelectTree || selectableActive) {
          return new Style({
            image: new Icon({
              src: selectableActive ? treeActiveImg : treeImg,
              scale: 0.55,
            }),
          })
        }
        const isOther = f.get('miniUserId') ? true : false
        const isHigh = f.get('my')
        if (!isHigh && !isOther) {
          return new Style({
            image: new Icon({
              src: treeImg,
              scale: 0.55,
            }),
          })
        }
        const img = f.get('icon')
        const count = 30
        const startColor = isHigh ? '#FFD887' : '#FFFFFFb3'
        const endColor = isHigh ? '#ED9E1E' : '#FFFFFFb3'
        const styles = [
          that.pointStyle(img, isHigh),
          that.progressStyle(count, isHigh),
          that.textBgStyle(count, startColor, endColor, isHigh),
        ]
        if (isHigh) {
          styles.push(
            that.activePointBgStyle(),
            that.statusTitleStyle(
              f.get('treeName'),
              0,
              -36,
              '#FFFFFF',
              '#B38A00',
              14,
              isHigh,
            ),
          )
          if (!localStorage.getItem('showMapText')) {
            styles.push(that.activeTextStyle())
          }
        }
        return styles
      },
    })
    kmap.addLayer(this.clusterLayer)
    this.kmap = kmap
  }

  setVisible(visible) {
    if (this.clusterLayer) {
      this.clusterLayer.setVisible(visible)
    }
  }

  setData(data, enterSelectTreeVal) {
    const that = this
    this.enterSelectTree = enterSelectTreeVal
    if (enterSelectTreeVal) {
      this.setVisible(false)
      this.clusterSource.clear()
      return
    }
    this.setVisible(true)
    this.clusterSource.clear()
    const features = []
    if (!data || !data.length) return
    const myPoint = data.find((item) => item.my)
    for (const item of data) {
      try {
        const f = newPoint(item, 'geom', 'cluster-point')
        features.push(f)
      } catch (err) {
        console.log('err', err)
      }
    }
    this.clusterSource.addFeatures(features)
    this.kmap.getView().fit(this.clusterSource.getExtent(), {
      duration: 1000,
      padding: [0, 10, 0, 10],
    })
    if (myPoint) {
      setTimeout(() => {
        const pointPosition = extractCoordinates(myPoint.geom)
        const view = this.kmap.getView()
        view.animate({
          duration: 1200,
          zoom: 20,
          center: pointPosition,
        })
      }, 1100)
    }
  }

  textBgStyle(count, startColor, endColor, isHigh) {
    const key = count + startColor + endColor + isHigh
    let style = this.textBgStyleCache[key]
    let length = 5
    let offsetX = 0
    let highOffsetX = 0

    if (count === 0) {
      length = 0
    } else if (count < 7) {
      length = 10
      offsetX = 14
      highOffsetX = 14
    } else if (count > 7 && count <= 14) {
      length = 20
      offsetX = 6
      highOffsetX = 7
    } else if (count > 14 && count <= 21) {
      length = 28
      offsetX = 4
      highOffsetX = 5
    } else if (count > 21 && count <= 29) {
      length = 34
      offsetX = 2
      highOffsetX = 3
    } else if (count === 30) {
      length = 38
      offsetX = 0
      highOffsetX = 0
    }
    if (!style) {
      style = new Style({
        renderer: function (coordinates, state) {
          const ctx = state.context
          const x =
            coordinates[0] -
            (isHigh ? highOffsetX * state.pixelRatio : offsetX * state.pixelRatio)
          const y =
            coordinates[1] + (isHigh ? 24 * state.pixelRatio : 17 * state.pixelRatio)
          const width = isHigh
            ? (length + 10) * state.pixelRatio
            : length * state.pixelRatio
          const height = isHigh ? 10 * state.pixelRatio : 6 * state.pixelRatio
          const cornerRadius = isHigh ? 5 * state.pixelRatio : 3 * state.pixelRatio
          const gradient = ctx.createLinearGradient(x - width / 2, y, x + width / 2, y)
          gradient.addColorStop(0, startColor)
          gradient.addColorStop(1, endColor)
          ctx.beginPath()
          ctx.moveTo(x - width / 2 + cornerRadius, y - height / 2)
          ctx.lineTo(x + width / 2 - cornerRadius, y - height / 2)
          ctx.arc(
            x + width / 2 - cornerRadius,
            y - height / 2 + cornerRadius,
            cornerRadius,
            -Math.PI / 2,
            0,
          )
          ctx.lineTo(x + width / 2, y + height / 2 - cornerRadius)
          ctx.arc(
            x + width / 2 - cornerRadius,
            y + height / 2 - cornerRadius,
            cornerRadius,
            0,
            Math.PI / 2,
          )
          ctx.lineTo(x - width / 2 + cornerRadius, y + height / 2)
          ctx.arc(
            x - width / 2 + cornerRadius,
            y + height / 2 - cornerRadius,
            cornerRadius,
            Math.PI / 2,
            Math.PI,
          )
          ctx.lineTo(x - width / 2, y - height / 2 + cornerRadius)
          ctx.arc(
            x - width / 2 + cornerRadius,
            y - height / 2 + cornerRadius,
            cornerRadius,
            Math.PI,
            -Math.PI / 2,
          )
          ctx.closePath()
          ctx.fillStyle = gradient
          ctx.fill()
        },
        zIndex: isHigh ? 12 : 10,
      })
      this.textBgStyleCache[key] = style
    }
    return style
  }

  statusTitleStyle(statusName, offsetX, offsetY, color, strokeColor, fontSize, isHigh) {
    const key = statusName + '-' + offsetY
    let style = this.statusTitleStyleCache[key]
    if (!style) {
      style = new Style({
        text: new Text({
          text: statusName,
          offsetX: offsetX,
          offsetY: offsetY,
          font: isHigh ? 'bold 14px sans-serif' : '12px sans-serif',
          fill: new Fill({ color }),
          stroke: new Stroke({ color: strokeColor }),
        }),
        zIndex: 13,
      })
      this.statusTitleStyleCache[key] = style
    }
    return style
  }

  pointStyle(img, isHigh) {
    const key = img + isHigh
    let bgStyle = this.bgStyleCache[key]
    if (!bgStyle) {
      bgStyle = new Style({
        image: new Photo({
          src: img,
          kind: 'circle',
          radius: isHigh ? 23 : 17,
          shadow: 0,
          crop: false,
          displacement: [0, 0],
          stroke: new Stroke({
            width: isHigh ? 0 : 1,
            color: isHigh ? '#fff' : '#C7C7C7',
          }),
        }),
        zIndex: isHigh ? 11 : 0,
      })
      this.bgStyleCache[key] = bgStyle
    }
    return bgStyle
  }

  activePointBgStyle() {
    return new Style({
      image: new Icon({
        src: activeBgImg,
        scale: 0.55,
      }),
      zIndex: 10,
    })
  }

  activeTextStyle() {
    return new Style({
      image: new Icon({
        src: hereImg,
        scale: 0.5,
        displacement: [0, 108],
      }),
      zIndex: 15,
    })
  }

  progressStyle(count, isHigh) {
    const key = count + isHigh
    let progressBgStyle = this.progressBgStyleCache[key]
    if (!progressBgStyle) {
      progressBgStyle = new Style({
        image: new Icon({
          src: isHigh ? progressActiveImg : progressImg,
          scale: 0.5,
          displacement: isHigh ? [0, -48] : [0, -34],
        }),
        zIndex: isHigh ? 12 : 0,
      })
      this.progressBgStyleCache[key] = progressBgStyle
    }
    return progressBgStyle
  }

  selectFeature(feature) {
    const fs = feature.get('features')
    if (!fs || fs.length === 0) {
      return feature
    }
    if (fs.length === 1) {
      return fs[0]
    }
    for (const item of fs) {
      if (item.get('my')) {
        return item
      }
    }
    for (const item of fs) {
      if (item.get('miniUserId')) {
        return item
      }
    }
    return fs[0]
  }
}

export default ClusterPointsLayer
