import * as KMap from '@/utils/ol-map/KMap.js'
import * as util from '@/common/ol_common.js'
import VectorLayer from 'ol/layer/Vector.js'
import { Vector as VectorSource } from 'ol/source'
import { newRegionFeature } from '@/utils/map.js'
import Style from 'ol/style/Style'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'
import Overlay from 'ol/Overlay'
import { getCenter } from 'ol/extent'
import { createRegionInfoCard, updateRegionInfoCard } from './regionInfoCard.js'

const FILL_DEFAULT = 'rgba(0, 0, 0, 0.4)'
const FILL_SELECTED = 'rgba(255, 166, 23, 0.25)'
const STROKE_DEFAULT = '#ffffff'
const STROKE_SELECTED = '#FFA617'

/**
 * 地图分区图层 + 分区信息框
 */
class RegionLayer {
  constructor(kmap, options = {}) {
    const that = this
    this.kmap = kmap
    this.enterSelectTree = !!options.enterSelectTree
    this.onRegionSelect = options.onRegionSelect
    this.selectedRegionId = null
    this.regionOverlays = []
    this._regionClickHandler = null
    this._selectedEntry = null
    this._styleCache = {
      normal: new Style({
        fill: new Fill({ color: FILL_DEFAULT }),
        stroke: new Stroke({ color: STROKE_DEFAULT, width: 1 }),
      }),
      selected: new Style({
        fill: new Fill({ color: FILL_SELECTED }),
        stroke: new Stroke({ color: STROKE_SELECTED, width: 2 }),
      }),
    }

    this.regionLayer = new KMap.VectorLayer('regionLayer', 99, {
      minZoom: 14.6,
      renderMode: 'image',
      updateWhileAnimating: false,
      updateWhileInteracting: false,
      style: (f) => that.getRegionStyle(f),
    })

    kmap.addLayer(this.regionLayer.layer)
  }

  get map() {
    return this.kmap.map
  }

  getRegionStyle(feature) {
    return feature.get('selected')
      ? [this._styleCache.selected]
      : [this._styleCache.normal]
  }

  getFeatureCenter(feature, item) {
    if (item?.pointWkt) {
      try {
        return util.wktCastGeom(item.pointWkt).getFirstCoordinate()
      } catch {
        /* ignore */
      }
    }
    const geom = feature.getGeometry()
    if (!geom) return null
    const type = geom.getType()
    if (type === 'Polygon' && typeof geom.getInteriorPoint === 'function') {
      return geom.getInteriorPoint().getCoordinates()
    }
    if (type === 'MultiPolygon' && typeof geom.getInteriorPoints === 'function') {
      const points = geom.getInteriorPoints()
      return points.getPoint(0).getCoordinates()
    }
    return getCenter(geom.getExtent())
  }

  clearRegionInfoOverlays() {
    this.regionOverlays.forEach(({ overlay }) => {
      this.map.removeOverlay(overlay)
    })
    this.regionOverlays = []
  }

  clearRegionClick() {
    if (this._regionClickHandler) {
      this.kmap.off('singleclick', this._regionClickHandler)
      this._regionClickHandler = null
    }
  }

  bindRegionClick() {
    this.clearRegionClick()
    const that = this
    this._regionClickHandler = (evt) => {
      if (!that.enterSelectTree) return
      let hit = null
      that.map.forEachFeatureAtPixel(
        evt.pixel,
        (feature, layer) => {
          if (layer !== that.regionLayer.layer) return
          const entry = that.regionOverlays.find((r) => r.feature === feature)
          if (entry) hit = entry
        },
        {
          layerFilter: (layer) => layer === that.regionLayer.layer,
          hitTolerance: 5,
        },
      )
      if (hit) that.selectRegion(hit)
    }
    this.kmap.on('singleclick', this._regionClickHandler)
  }

  selectRegion(entry) {
    if (!this.enterSelectTree || !entry) return
    if (this._selectedEntry === entry) return

    const prev = this._selectedEntry
    if (prev) {
      prev.feature.set('selected', false)
      updateRegionInfoCard(prev.el, {
        enterSelectTree: true,
        selected: false,
      })
    }

    entry.feature.set('selected', true)
    this._selectedEntry = entry
    this.selectedRegionId = entry.item.id ?? entry.item.regionId ?? entry.feature.getId()
    updateRegionInfoCard(entry.el, {
      enterSelectTree: true,
      selected: true,
    })

    // 合并为一次图层刷新，减轻 Canvas 矢量层整层重绘闪烁
    const source = this.regionLayer.layer.getSource()
    if (source) {
      source.changed()
    }

    if (typeof this.onRegionSelect === 'function') {
      this.onRegionSelect(entry.item, entry.feature)
    }
  }

  addRegionInfoOverlay(item, feature) {
    const coord = this.getFeatureCenter(feature, item)
    if (!coord) return null

    const entry = { item, feature, el: null, overlay: null }
    const el = createRegionInfoCard(item, {
      enterSelectTree: this.enterSelectTree,
      selected: false,
      onClick: () => this.selectRegion(entry),
    })
    entry.el = el

    const overlay = new Overlay({
      element: el,
      position: coord,
      positioning: 'bottom-center',
      stopEvent: this.enterSelectTree,
      offset: [0, -4],
    })
    entry.overlay = overlay
    this.map.addOverlay(overlay)
    if (this.enterSelectTree) this.bindCardClick(entry)
    return entry
  }

  bindCardClick(entry) {
    if (!entry.el || entry.el._regionSelectBound) return
    entry.el.addEventListener('click', (e) => {
      e.stopPropagation()
      if (this.enterSelectTree) this.selectRegion(entry)
    })
    entry.el._regionSelectBound = true
  }

  setEnterSelectTree(val) {
    this.enterSelectTree = !!val
    this.regionOverlays.forEach((r) => {
      updateRegionInfoCard(r.el, {
        enterSelectTree: this.enterSelectTree,
        selected: !!r.feature.get('selected'),
      })
      if (r.el) {
        r.el.style.pointerEvents = this.enterSelectTree ? 'auto' : 'none'
        if (this.enterSelectTree) this.bindCardClick(r)
      }
      if (r.overlay?.setStopEvent) {
        r.overlay.setStopEvent(this.enterSelectTree)
      }
    })
    if (this.enterSelectTree) {
      this.bindRegionClick()
    } else {
      this.clearRegionClick()
      this.regionOverlays.forEach((r) => {
        r.feature.set('selected', false)
        updateRegionInfoCard(r.el, { enterSelectTree: false, selected: false })
      })
      this.selectedRegionId = null
      this._selectedEntry = null
      this.regionLayer.layer.getSource()?.changed()
    }
  }

  initData(data) {
    this.clearLayer()
    if (!data || !data.length) return

    const features = []
    for (const item of data) {
      item.regionWkt = item.regionWkt || item.wkt
      if (!item.regionWkt) {
        console.warn('[regionLayer] 分区缺少 wkt', item)
        continue
      }
      try {
        const f = newRegionFeature({
          ...item,
          bgName: 'defalut',
          bgColor: 'defalut',
          selected: false,
        })
        features.push(f)

        const entry = this.addRegionInfoOverlay(item, f)
        if (entry) {
          this.regionOverlays.push(entry)
        }
      } catch (err) {
        console.warn('[regionLayer] 解析分区失败', item, err)
      }
    }

    this.area = features
    const source = new VectorSource({ features })
    this.regionLayer.layer.setSource(source)

    if (features.length) {
      const extent = source.getExtent()
      if (extent.every((n) => Number.isFinite(n))) {
        this.kmap.getView().fit(extent, {
          padding: [60, 40, 100, 40],
          duration: 600,
          maxZoom: 19,
        })
      }
    }

    if (this.enterSelectTree) {
      this.bindRegionClick()
    }
  }

  clearLayer() {
    this.clearRegionClick()
    this.clearRegionInfoOverlays()
    this.selectedRegionId = null
    this._selectedEntry = null
    if (this.regionLayer?.layer?.getSource()) {
      this.regionLayer.layer.getSource().clear()
    }
  }

  reset(farm) {
    this.clearLayer()
    this.initData(farm?.id ? [] : [])
  }
}

export default RegionLayer
