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 XYZ from 'ol/source/XYZ.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)

// 视图投影：使用 EPSG:3857（Web墨卡托），与天地图瓦片一致，无需重投影
const PROJ = 'EPSG:3857'

// 天地图Key（环境变量优先，未配置时使用默认值）
const TIANDITU_KEY = import.meta.env.VITE_TIANDITU_KEY || '2d46608fc30b02c5855c5dc662e7d33a'

// 天地图瓦片URL（WMTS，EPSG:3857）—— 固定 t0 子域，避免 {s} 替换问题
function tiandituUrl(layer) {
  return `https://t0.tianditu.gov.cn/${layer}_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layer}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${TIANDITU_KEY}`
}

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

    // 天地图矢量底图 + 注记图层（国内可访问，EPSG:3857 与视图一致，直接渲染）
    const baseLayer = new TileLayer({
      source: new XYZ({
        url: tiandituUrl('vec'),
        maxZoom: 18,
      }),
    })
    // 天地图矢量注记（地名标注层）
    const labelLayer = new TileLayer({
      source: new XYZ({
        url: tiandituUrl('cva'),
        maxZoom: 18,
      }),
    })

    // 瓦片加载诊断日志（兼容不同OL版本，绝不让日志抛错中断渲染）
    const getTileSrc = (e) => {
      try {
        const t = e.tile
        if (!t) return 'unknown'
        if (typeof t.getSrc === 'function') return t.getSrc()
        if (t.src) return t.src
        if (t.getImage && typeof t.getImage === 'function') {
          const img = t.getImage()
          return img && img.src ? img.src : 'no-src'
        }
        return 'unknown-tile'
      } catch (err) {
        return 'log-error'
      }
    }
    baseLayer.getSource().on('tileloaderror', (e) => {
      console.error('[Map] 底图瓦片加载失败:', getTileSrc(e))
    })
    labelLayer.getSource().on('tileloaderror', (e) => {
      console.error('[Map] 注记瓦片加载失败:', getTileSrc(e))
    })

    const olView = new View({
      projection: PROJ,
      // center 参数约定为 [纬度, 经度]，内部转换为 fromLonLat 需要的 [经度, 纬度]
      center: fromLonLat([center[1], center[0]], PROJ),
      zoom: zoom ?? DEFAULT_ZOOM,
    })

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

    // 确保容器渲染完成后刷新尺寸（解决容器高度为0时瓦片不显示的问题）
    setTimeout(() => {
      olMap.updateSize()
      console.log('[Map] 容器尺寸:', container.clientWidth, 'x', container.clientHeight)
      console.log('[Map] 地图尺寸:', olMap.getSize())
    }, 200)

    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,
  }
}
