import { ref, onBeforeUnmount } from 'vue'
import Map from 'ol/Map.js'
import View from 'ol/View.js'
import TileLayer from 'ol/layer/Tile.js'
import VectorLayer from 'ol/layer/Vector.js'
import VectorSource from 'ol/source/Vector.js'
import OSM from 'ol/source/OSM.js'
import Feature from 'ol/Feature.js'
import Point from 'ol/geom/Point.js'
import Polygon from 'ol/geom/Polygon.js'
import LineString from 'ol/geom/LineString.js'
import { Style, Circle as CircleStyle, Fill, Stroke, Text as TextStyle } from 'ol/style.js'
import Overlay from 'ol/Overlay.js'
import { fromLonLat, toLonLat } from 'ol/proj.js'
import proj4 from 'proj4'
import { register } from 'ol/proj/proj4.js'
import { DEFAULT_CENTER, DEFAULT_ZOOM, TBA_BASIN_PATHS } from '@/utils/gis-config'

proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs +type=crs')
register(proj4)

const PROJ = 'EPSG:4490'

export function useMap() {
  const map = ref(null)
  const view = ref(null)
  const coord = ref({ lng: 0, lat: 0 })

  let popupOverlay = null
  let basinLayer = null
  const layerRegistry = {}

  function getPopupOverlay() {
    if (popupOverlay) return popupOverlay
    const el = document.createElement('div')
    el.className = 'ol-popup-custom'
    el.innerHTML = '<a href="#" class="ol-popup-closer">&times;</a><div class="ol-popup-content-inner"></div>'
    el.querySelector('.ol-popup-closer').onclick = (e) => {
      e.preventDefault()
      el.style.display = 'none'
    }
    el.style.cssText = 'position:absolute;background:#fff;border-radius:6px;box-shadow:0 2px 12px rgba(0,0,0,0.15);padding:10px 14px;font-size:13px;min-width:180px;z-index:9999'
    const closer = el.querySelector('.ol-popup-closer')
    closer.style.cssText = 'position:absolute;top:2px;right:6px;font-size:16px;color:#999;text-decoration:none;line-height:1'
    document.body.appendChild(el)
    popupOverlay = new Overlay({ element: el, positioning: 'bottom-center', stopEvent: true, offset: [0, -10] })
    return popupOverlay
  }

  async function initMap(containerId, center, zoom) {
    const container = typeof containerId === 'string' ? document.getElementById(containerId) : containerId

    const baseLayer = new TileLayer({
      source: new OSM(),
    })

    const olView = new View({
      projection: PROJ,
      center: center ? fromLonLat(center, PROJ) : fromLonLat(DEFAULT_CENTER, PROJ),
      zoom: zoom ?? DEFAULT_ZOOM,
    })

    const olMap = new Map({
      target: container,
      layers: [baseLayer],
      view: olView,
    })

    olMap.on('pointermove', (evt) => {
      if (evt.dragging) return
      const ll = toLonLat(evt.coordinate, PROJ)
      coord.value = { lng: +ll[0].toFixed(6), lat: +ll[1].toFixed(6) }
    })

    map.value = olMap
    view.value = olView

    return { map: olMap, view: olView }
  }

  async function ensureModules() {}

  async function getModule() { return null }

  function createGraphicsLayer(id) {
    const source = new VectorSource()
    const layer = new VectorLayer({ source })

    const wrapper = {
      id, _source: source, _layer: layer,
      add(feature) { source.addFeature(feature) },
      removeAll() { source.clear() },
      get visible() { return layer.getVisible() },
      set visible(v) { layer.setVisible(v) },
    }

    layerRegistry[id] = wrapper
    if (map.value) map.value.addLayer(layer)
    return wrapper
  }

  function createPointMarker(lat, lng, style, attrs) {
    const feature = new Feature(new Point(fromLonLat([lng, lat], PROJ)))
    if (style) feature.setStyle(style)
    if (attrs) {
      feature.set('_attrs', attrs)
      Object.keys(attrs).forEach(k => feature.set(k, attrs[k]))
    }
    return feature
  }

  function hexToRgba(hex, alpha) {
    const r = parseInt(hex.slice(1, 3), 16)
    const g = parseInt(hex.slice(3, 5), 16)
    const b = parseInt(hex.slice(5, 7), 16)
    const a = alpha != null ? alpha / 255 : 0.8
    return `rgba(${r},${g},${b},${a})`
  }

  function createCircleSymbol(color, radius, opacity) {
    return new Style({
      image: new CircleStyle({
        radius: (radius || 14) / 2,
        fill: new Fill({ color: hexToRgba(color, opacity) }),
        stroke: new Stroke({ color: '#fff', width: 1.5 }),
      }),
    })
  }

  function createDefaultSymbol() {
    return new Style({
      image: new CircleStyle({
        radius: 7,
        fill: new Fill({ color: 'rgba(64,158,255,0.8)' }),
        stroke: new Stroke({ color: '#fff', width: 1.5 }),
      }),
    })
  }

  function openPopup(viewOrMapInstance, title, content, location) {
    const overlay = getPopupOverlay()
    overlay.getElement().style.display = ''
    const inner = overlay.getElement().querySelector('.ol-popup-content-inner')
    inner.innerHTML = `<div style="font-weight:600;font-size:14px;margin-bottom:6px;border-bottom:1px solid #eee;padding-bottom:4px">${title}</div><div>${content}</div>`

    let pos
    if (Array.isArray(location)) {
      pos = fromLonLat(location, PROJ)
    } else if (location instanceof Point) {
      pos = location.getCoordinates()
    } else if (location && location.getGeometry) {
      pos = location.getGeometry().getCoordinates()
    } else {
      pos = fromLonLat(DEFAULT_CENTER, PROJ)
    }

    overlay.setPosition(pos)
    const mapInst = viewOrMapInstance instanceof Map ? viewOrMapInstance : map.value
    mapInst.addOverlay(overlay)
  }

  function closePopup() {
    if (popupOverlay) popupOverlay.getElement().style.display = 'none'
  }

  async function addBasinBoundary() {
    if (!map.value) return
    if (basinLayer) { map.value.removeLayer(basinLayer); basinLayer = null }
    const coords = TBA_BASIN_PATHS.map(p => fromLonLat(p, PROJ))
    const feature = new Feature(new Polygon([coords]))
    feature.setStyle(new Style({
      stroke: new Stroke({ color: 'rgba(72,149,239,0.7)', width: 2 }),
      fill: new Fill({ color: 'rgba(72,149,239,0.06)' }),
    }))
    const source = new VectorSource({ features: [feature] })
    basinLayer = new VectorLayer({ source })
    map.value.addLayer(basinLayer)
  }

  function destroy() {
    if (popupOverlay) { popupOverlay.getElement()?.remove(); popupOverlay = null }
    if (map.value) { map.value.setTarget(null); map.value = null }
    view.value = null
  }

  onBeforeUnmount(destroy)

  function findLayer(id) {
    return layerRegistry[id] || null
  }

  function removeLayer(layer) {
    if (layer && layer._layer && map.value) {
      map.value.removeLayer(layer._layer)
      delete layerRegistry[layer.id]
    }
  }

  function addLayerToMap(layer) {
    if (layer && layer._layer && map.value) {
      map.value.addLayer(layer._layer)
    }
  }

  return {
    map, view, coord,
    initMap, ensureModules, getModule,
    createGraphicsLayer, createPointMarker, createCircleSymbol, createDefaultSymbol,
    openPopup, closePopup, addBasinBoundary, destroy,
    findLayer, removeLayer, addLayerToMap,
  }
}
