// ============================================================
// 电子围栏 Composable — 养老/医疗场景
//
// 功能：
//   1. 绘制围栏（多边形 / 圆形）
//   2. 添加老人标记（👴 可拖拽 + 方向键移动）
//   3. 越界检测（围栏 vs 老人位置）
//   4. 声光报警（越界时触发）
// ============================================================

import { ref, shallowRef, computed } from 'vue'
import type { Ref } from 'vue'
import { loadAMap } from './useAmap'

// ─── 常量 ────────────────────────────────────────────

/** 围栏默认样式 */
const FENCE_STYLE = {
  fillColor: 'rgba(66, 184, 131, 0.18)',
  strokeColor: '#42b883',
  strokeWeight: 2,
  strokeOpacity: 0.9,
  strokeStyle: 'solid' as const,
}

/** 围栏告警样式 */
const FENCE_ALARM_STYLE = {
  fillColor: 'rgba(255, 77, 79, 0.25)',
  strokeColor: '#FF4D4F',
  strokeWeight: 3,
  strokeOpacity: 1,
  strokeStyle: 'dashed' as const,
}

/** 绘制时预览线样式 */
const DRAW_LINE_STYLE = {
  strokeColor: '#42b883',
  strokeWeight: 2,
  strokeOpacity: 0.6,
  strokeStyle: 'dashed' as const,
}

/** 老人标记 HTML（使用全局 CSS 类） */
const PERSON_MARKER_HTML = '<div class="geofence-person-marker">👴</div>'

/** 普通顶点标记（使用全局 CSS 类） */
function vertexMarkerHTML(index: number): string {
  return `<div class="geofence-vertex-dot">${index}</div>`
}

// ─── 工具函数 ────────────────────────────────────────

/** 射线法判断点是否在多边形内（兜底方案，AMap 不内置此方法） */
function isPointInPolygon(
  point: [number, number],
  polygon: [number, number][]
): boolean {
  const [x, y] = point
  let inside = false
  const n = polygon.length
  for (let i = 0, j = n - 1; i < n; j = i++) {
    const [xi, yi] = polygon[i]
    const [xj, yj] = polygon[j]
    if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
      inside = !inside
    }
  }
  return inside
}

// ─── 类型 ────────────────────────────────────────────

export interface AlarmRecord {
  time: string
  position: [number, number]
}

// ─── Composable ──────────────────────────────────────

export function useGeofence(mapInstance: Ref<AMap.Map | null>) {
  // ========== 状态 ==========

  /** 当前围栏覆盖物 */
  const fenceOverlay = shallowRef<AMap.Polygon | AMap.Circle | null>(null)
  /** 围栏类型 */
  const fenceType = ref<'polygon' | 'circle' | null>(null)
  /** 圆形围栏参数 */
  const circleCenter = ref<[number, number] | null>(null)
  const circleRadius = ref(0)
  /** 多边形顶点（用于出入判断） */
  const fenceVertices = ref<[number, number][]>([])

  /** 是否正在绘制 */
  const isDrawing = ref(false)
  /** 绘制时的预览线 */
  const drawLine = shallowRef<AMap.Polyline | null>(null)
  /** 绘制时的顶点标记列表 */
  const vertexMarkers = shallowRef<AMap.Marker[]>([])
  /** 当前已绘制的顶点数（用于模板判断是否 >= 3 个） */
  const drawVertexCount = ref(0)

  /** 老人标记 */
  const personMarker = shallowRef<AMap.Marker | null>(null)
  /** 老人当前位置 */
  const personPosition = ref<[number, number] | null>(null)

  /** 老人是否在围栏内 */
  const isInside = ref(true)
  /** 报警是否激活 */
  const alarmActive = ref(false)
  /** 越界次数 */
  const alarmCount = ref(0)
  /** 报警历史 */
  const alarmHistory = ref<AlarmRecord[]>([])
  /** 报警音效振荡器引用 */
  let alarmOscillator: OscillatorNode | null = null
  let alarmGain: GainNode | null = null
  let alarmInterval: ReturnType<typeof setInterval> | null = null

  /** 是否已有围栏（可用于模板判断） */
  const hasFence = computed(() => fenceOverlay.value !== null)
  /** 是否已有老人标记 */
  const hasPerson = computed(() => personMarker.value !== null)

  // ========== 围栏绘制 ==========

  /** 绘制时的暂存顶点（闭包内引用，供 finishDraw 访问） */
  let _drawPoints: [number, number][] = []

  /**
   * 启动多边形围栏绘制
   *
   * 交互：
   *   - 在地图上逐一点击添加顶点（绿色编号圆点 + 虚线连线）
   *   - 点击首顶点附近（±15 像素范围）→ 闭环完成 ✅
   *   - 点击「闭合围栏」按钮 → 闭环完成 ✅
   *   - 右键或 Esc → 取消 🗑️
   *
   * 解决双击冲突：禁用 AMap 的双击缩放（doubleClickZoom = false），
   * 避免双击 = click+click+dblclick 的竞态。
   */
  async function startDrawPolygon(): Promise<void> {
    const map = mapInstance.value
    if (!map) return

    // 清理上一个绘制状态
    cancelDraw()

    const AMap = await loadAMap()

    const points: [number, number][] = []
    _drawPoints = points
    isDrawing.value = true
    fenceType.value = 'polygon'
    drawVertexCount.value = 0

    // 关键：禁用双击缩放，否则 dblclick 被 AMap 消耗
    map.setStatus({ doubleClickZoom: false })

    // ── 点击事件：添加顶点 或 闭环 ──
    function onClick(e: any): void {
      // 安全获取经纬度（兼容 LngLat 实例 / 普通对象 / getter 多种形式）
      const lnglat = e.lnglat
      const lng: number = typeof lnglat.lng === 'number'
        ? lnglat.lng
        : lnglat.getLng?.() ?? NaN
      const lat: number = typeof lnglat.lat === 'number'
        ? lnglat.lat
        : lnglat.getLat?.() ?? NaN

      if (isNaN(lng) || isNaN(lat)) return

      const clicked: [number, number] = [lng, lat]

      // 已有 >= 3 个顶点 + 点击位置接近首顶点（地理距离 < 30 米） → 闭环
      if (points.length >= 3) {
        const distToFirst = haversineDistance(clicked, points[0])
        if (distToFirst < 30) {
          finishPolygonDraw(points, map!, AMap)
          return
        }
      }

      // 普通点击：添加顶点
      points.push(clicked)
      drawVertexCount.value = points.length

      // 添加编号顶点标记
      const vm = new AMap.Marker({
        position: clicked,
        content: vertexMarkerHTML(points.length),
        offset: new AMap.Pixel(-6, -6),
        zIndex: 120,
      })
      map!.add(vm)
      vertexMarkers.value = [...vertexMarkers.value, vm]

      // 更新预览线
      if (drawLine.value) {
        drawLine.value.setPath(points)
      } else {
        drawLine.value = new AMap.Polyline({
          path: points,
          ...DRAW_LINE_STYLE,
          zIndex: 110,
        })
        map!.add(drawLine.value)
      }

      // 更新首顶点样式：销毁并重建为首顶点专用高亮标记
      if (points.length >= 3 && vertexMarkers.value[0]) {
        const oldFirst = vertexMarkers.value[0]
        const firstPos = oldFirst.getPosition()
        map!.remove(oldFirst)

        const highlightedFirst = new AMap.Marker({
          position: [firstPos.lng, firstPos.lat],
          content: `<div class="geofence-first-vertex">1</div>`,
          offset: new AMap.Pixel(-10, -10),
          zIndex: 125, // 高于其他顶点
        })
        map!.add(highlightedFirst)

        // 替换数组中的第一个
        const rest = vertexMarkers.value.slice(1)
        vertexMarkers.value = [highlightedFirst, ...rest]
      }
    }

    // ── 右键：取消绘制 ──
    function onRightClick(e: any): void {
      // 阻止浏览器默认右键菜单
      e.domEvent?.preventDefault?.()
      cancelDraw()
    }

    // 绑定事件
    ;(map as any)._geofenceClick = onClick
    ;(map as any)._geofenceRightClick = onRightClick

    map.on('click', onClick)
    map.on('rightclick', onRightClick)

    // 切换光标为十字
    map.setDefaultCursor('crosshair')
  }

  /** 手动闭合多边形（供 UI 按钮调用） */
  async function finishDraw(): Promise<void> {
    const map = mapInstance.value
    if (!map || !isDrawing.value) return

    const AMap = await loadAMap()

    if (fenceType.value === 'polygon') {
      finishPolygonDraw(_drawPoints, map, AMap)
    }
    // 圆形暂不支持手动完成（只能点击第二次完成）
  }

  /** 完成多边形绘制，创建最终围栏 */
  function finishPolygonDraw(
    points: [number, number][],
    map: AMap.Map,
    AMap: typeof import('@amap/amap-jsapi-loader')
  ): void {
    if (points.length < 3) {
      cancelDraw()
      alert('至少需要 3 个顶点才能形成电子围栏。请继续点击添加更多顶点。')
      return
    }

    // 清理绘制中间状态（预览线、顶点标记、事件监听）
    cleanupDrawing(map)
    isDrawing.value = false
    drawVertexCount.value = 0
    _drawPoints = []

    // 恢复双击缩放
    map.setStatus({ doubleClickZoom: true })

    // 创建围栏多边形
    const polygon = new AMap.Polygon({
      path: points,
      ...FENCE_STYLE,
      zIndex: 100,
    })
    map.add(polygon)
    fenceOverlay.value = polygon
    fenceVertices.value = [...points]

    map.setDefaultCursor('default')

    console.log(`[电子围栏] ✅ 多边形围栏已创建，顶点数: ${points.length}`)
  }

  /** 启动圆形围栏绘制 */
  async function startDrawCircle(): Promise<void> {
    const map = mapInstance.value
    if (!map) return

    cancelDraw()

    const AMap = await loadAMap()
    isDrawing.value = true
    fenceType.value = 'circle'
    drawVertexCount.value = 0

    // 禁用双击缩放
    map.setStatus({ doubleClickZoom: false })

    let centerPoint: [number, number] | null = null
    let previewCircle: AMap.Circle | null = null

    // ── 第一次点击：确定圆心 ──
    function onClick(e: any): void {
      const lng = e.lnglat.getLng()
      const lat = e.lnglat.getLat()

      if (!centerPoint) {
        // 设置圆心
        centerPoint = [lng, lat]
        map!.off('click', onClick)

        // 添加圆心标记
        const cm = new AMap.Marker({
          position: [lng, lat],
          content: `<div style="width:16px;height:16px;border-radius:50%;background:#FF4D4F;border:2px solid #fff;box-shadow:0 1px 6px rgba(0,0,0,0.3);"></div>`,
          offset: new AMap.Pixel(-8, -8),
          zIndex: 120,
        })
        map!.add(cm)
        vertexMarkers.value = [cm]

        // 监听鼠标移动，动态预览圆形
        function onMouseMove(me: any): void {
          const mlng = me.lnglat.getLng()
          const mlat = me.lnglat.getLat()
          const r = haversineDistance(centerPoint!, [mlng, mlat])

          if (previewCircle) {
            previewCircle.setCenter(centerPoint!)
            previewCircle.setRadius(r)
          } else {
            previewCircle = new AMap.Circle({
              center: centerPoint!,
              radius: r,
              fillColor: 'rgba(66, 184, 131, 0.12)',
              fillOpacity: 0.3,
              strokeColor: '#42b883',
              strokeWeight: 2,
              strokeOpacity: 0.6,
              strokeStyle: 'dashed',
              zIndex: 110,
            })
            map!.add(previewCircle)
          }
        }

        function onSecondClick(se: any): void {
          const slng = se.lnglat.getLng()
          const slat = se.lnglat.getLat()
          const r = haversineDistance(centerPoint!, [slng, slat])

          map!.off('mousemove', onMouseMove)
          map!.off('click', onSecondClick)

          // 清理预览
          if (previewCircle) {
            map!.remove(previewCircle)
            previewCircle = null
          }
          cleanupDrawing(map!)
          isDrawing.value = false
          drawVertexCount.value = 0

          // 创建正式围栏
          const circle = new AMap.Circle({
            center: centerPoint!,
            radius: r,
            ...FENCE_STYLE,
            zIndex: 100,
          })
          map!.add(circle)
          fenceOverlay.value = circle
          circleCenter.value = centerPoint
          circleRadius.value = r
          fenceVertices.value = [centerPoint!]

          // 恢复双击缩放
          map!.setStatus({ doubleClickZoom: true })
          map!.setDefaultCursor('default')
          console.log(`[电子围栏] ✅ 圆形围栏已创建，半径: ${Math.round(r)}米`)
        }

        // ── 右键取消 ──
        function onCircleRightClick(e: any): void {
          e.domEvent?.preventDefault?.()
          map!.off('mousemove', onMouseMove)
          map!.off('click', onSecondClick)
          cancelDraw()
        }

        ;(map as any)._geofenceSecondClick = onSecondClick
        ;(map as any)._geofenceMouseMove = onMouseMove
        ;(map as any)._geofenceCircleRightClick = onCircleRightClick
        map!.on('click', onSecondClick)
        map!.on('mousemove', onMouseMove)
        map!.on('rightclick', onCircleRightClick)
      }
    }

    // ── 绘制阶段的右键取消 ──
    function onCancelRightClick(e: any): void {
      e.domEvent?.preventDefault?.()
      cancelDraw()
    }

    ;(map as any)._geofenceClick = onClick
    ;(map as any)._geofenceCircleCancelRight = onCancelRightClick
    map.on('click', onClick)
    map.on('rightclick', onCancelRightClick)
    map.setDefaultCursor('crosshair')
  }

  /** 取消当前绘制 */
  function cancelDraw(): void {
    const map = mapInstance.value
    if (!map) return

    cleanupDrawing(map)
    isDrawing.value = false
    drawVertexCount.value = 0
    _drawPoints = []

    // 恢复双击缩放
    map.setStatus({ doubleClickZoom: true })
    map.setDefaultCursor('default')
  }

  /** 清理绘制中的中间元素 */
  function cleanupDrawing(map: AMap.Map): void {
    // 移除预览线
    if (drawLine.value) {
      map.remove(drawLine.value)
      drawLine.value = null
    }
    // 移除顶点标记
    vertexMarkers.value.forEach((m) => map.remove(m))
    vertexMarkers.value = []

    // 移除事件监听
    const m = map as any
    if (m._geofenceClick) { map.off('click', m._geofenceClick); delete m._geofenceClick }
    if (m._geofenceRightClick) { map.off('rightclick', m._geofenceRightClick); delete m._geofenceRightClick }
    if (m._geofenceSecondClick) { map.off('click', m._geofenceSecondClick); delete m._geofenceSecondClick }
    if (m._geofenceMouseMove) { map.off('mousemove', m._geofenceMouseMove); delete m._geofenceMouseMove }
    if (m._geofenceCircleRightClick) { map.off('rightclick', m._geofenceCircleRightClick); delete m._geofenceCircleRightClick }
    if (m._geofenceCircleCancelRight) { map.off('rightclick', m._geofenceCircleCancelRight); delete m._geofenceCircleCancelRight }

    // 恢复双击缩放
    map.setStatus({ doubleClickZoom: true })
  }

  /** 删除当前围栏 */
  function clearFence(): void {
    const map = mapInstance.value
    if (!map) return

    if (fenceOverlay.value) {
      map.remove(fenceOverlay.value)
      fenceOverlay.value = null
    }
    fenceType.value = null
    fenceVertices.value = []
    circleCenter.value = null
    circleRadius.value = 0
    isInside.value = true
    alarmActive.value = false
    stopAlarmSound()
    console.log('[电子围栏] 🗑️ 围栏已清除')
  }

  // ========== 老人标记 ==========

  /** 在地图中心添加老人标记 */
  async function addPerson(): Promise<void> {
    const map = mapInstance.value
    if (!map) return

    // 先移除旧标记
    removePerson()

    const AMap = await loadAMap()

    // 默认放在地图当前中心
    const center = map.getCenter()
    const position: [number, number] = [center.lng, center.lat]

    // 如果围栏存在，放在围栏内部
    if (fenceOverlay.value && fenceType.value === 'polygon') {
      // 尝试放在第一个顶点的附近（围栏内部）
      const v0 = fenceVertices.value[0]
      if (v0) {
        position[0] = v0[0] + 0.001 // 稍偏移
        position[1] = v0[1] + 0.001
      }
    }

    const marker = new AMap.Marker({
      position,
      content: PERSON_MARKER_HTML,
      offset: new AMap.Pixel(-17, -17),
      draggable: true,
      zIndex: 200,
    })

    // 拖拽结束 → 检测越界
    marker.on('dragend', () => {
      const pos = marker.getPosition()
      personPosition.value = [pos.lng, pos.lat]
      checkBoundary()
    })

    map.add(marker)
    personMarker.value = marker
    personPosition.value = position

    // 创建后立刻检测位置
    checkBoundary()

    console.log(`[电子围栏] 👴 老人已添加，位置: [${position[0].toFixed(5)}, ${position[1].toFixed(5)}]`)
  }

  /** 移除老人标记 */
  function removePerson(): void {
    const map = mapInstance.value
    if (!map) return

    if (personMarker.value) {
      map.remove(personMarker.value)
      personMarker.value = null
    }
    personPosition.value = null
    isInside.value = true
    alarmActive.value = false
    stopAlarmSound()
  }

  // ========== 移动控制 ==========

  /** 步长（经纬度偏移），约 20-50 米 */
  const MOVE_STEP = 0.0005

  /** 方向移动老人 */
  function movePerson(direction: 'up' | 'down' | 'left' | 'right'): void {
    const marker = personMarker.value
    if (!marker) return

    const pos = marker.getPosition()
    let { lng, lat } = pos

    switch (direction) {
      case 'up':    lat += MOVE_STEP; break
      case 'down':  lat -= MOVE_STEP; break
      case 'left':  lng -= MOVE_STEP; break
      case 'right': lng += MOVE_STEP; break
    }

    const newPosition: [number, number] = [lng, lat]
    marker.setPosition(newPosition)
    personPosition.value = newPosition

    // 每次移动后检测越界
    checkBoundary()
  }

  // ========== 越界检测 ==========

  /**
   * 检测老人是否在围栏内
   * 更新 isInside / alarmActive，必要时触发报警
   */
  function checkBoundary(): void {
    const pp = personPosition.value
    if (!pp) return

    const fence = fenceOverlay.value
    if (!fence) {
      // 没有围栏，不判断
      isInside.value = true
      return
    }

    let inside: boolean

    if (fenceType.value === 'circle') {
      // 圆形：使用 AMap.Circle.contains()
      inside = (fence as AMap.Circle).contains(pp)
    } else {
      // 多边形：先用 GeometryUtil，兜底用射线法
      const AMap = (window as any).AMap
      try {
        inside = AMap.GeometryUtil.isPointInRing(
          { lng: pp[0], lat: pp[1] },
          fenceVertices.value
        )
      } catch {
        inside = isPointInPolygon(pp, fenceVertices.value)
      }
    }

    const wasInside = isInside.value
    isInside.value = inside

    if (!inside && wasInside) {
      // ── 刚刚越界！触发报警 ──
      triggerAlarm(pp)
    }

    if (inside && !wasInside) {
      // ── 回到围栏内 ──
      resetAlarm()
      updateFenceStyle(false)
    }
  }

  // ========== 报警 ==========

  function triggerAlarm(position: [number, number]): void {
    if (alarmActive.value) return // 已激活，不重复

    alarmActive.value = true
    alarmCount.value++
    alarmHistory.value.push({
      time: new Date().toLocaleTimeString('zh-CN'),
      position,
    })

    updateFenceStyle(true)
    startAlarmSound()

    console.warn(`[电子围栏] 🚨 第 ${alarmCount.value} 次越界报警！位置: [${position[0].toFixed(5)}, ${position[1].toFixed(5)}]`)
  }

  function resetAlarm(): void {
    alarmActive.value = false
    stopAlarmSound()
    updateFenceStyle(false)
    console.log('[电子围栏] ✅ 老人已回到围栏内')
  }

  /** 手动解除报警 */
  function dismissAlarm(): void {
    alarmActive.value = false
    stopAlarmSound()
    updateFenceStyle(false)
  }

  /** 围栏样式切换 */
  function updateFenceStyle(alarm: boolean): void {
    const fence = fenceOverlay.value
    if (!fence) return

    const style = alarm ? FENCE_ALARM_STYLE : FENCE_STYLE
    if (fenceType.value === 'polygon') {
      const poly = fence as AMap.Polygon
      poly.setOptions?.(style) || Object.assign(poly as any, style)
    } else {
      const circle = fence as AMap.Circle
      circle.setOptions?.(style) || Object.assign(circle as any, style)
    }
  }

  /** 播放报警音（Web Audio API — 蜂鸣声） */
  function startAlarmSound(): void {
    stopAlarmSound()

    try {
      const AudioCtx = window.AudioContext || (window as any).webkitAudioContext
      if (!AudioCtx) return

      const ctx = new AudioCtx()

      function beep(): void {
        const osc = ctx.createOscillator()
        const gain = ctx.createGain()
        osc.connect(gain)
        gain.connect(ctx.destination)

        osc.type = 'square'
        osc.frequency.value = 880
        gain.gain.value = 0.2

        osc.start(ctx.currentTime)
        gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3)
        osc.stop(ctx.currentTime + 0.3)

        alarmOscillator = osc
        alarmGain = gain
      }

      // 每 800ms 蜂鸣一次
      beep()
      alarmInterval = setInterval(() => {
        beep()
      }, 800)
    } catch {
      // 静默失败（部分环境不支持 Web Audio）
    }
  }

  /** 停止报警音 */
  function stopAlarmSound(): void {
    if (alarmInterval) {
      clearInterval(alarmInterval)
      alarmInterval = null
    }
    try {
      alarmOscillator?.stop?.()
      alarmGain?.disconnect?.()
    } catch { /* ignore */ }
    alarmOscillator = null
    alarmGain = null
  }

  // ========== 生命周期清理 ==========

  /** 销毁所有围栏相关资源 */
  function destroyGeofence(): void {
    stopAlarmSound()
    clearFence()
    removePerson()
    cancelDraw()
  }

  return {
    // 状态
    fenceOverlay,
    fenceType,
    fenceVertices,
    isDrawing,
    isInside,
    alarmActive,
    alarmCount,
    alarmHistory,
    hasFence,
    hasPerson,
    personMarker,
    personPosition,

    // 围栏操作
    startDrawPolygon,
    startDrawCircle,
    finishDraw,
    cancelDraw,
    clearFence,
    drawVertexCount,

    // 老人标记操作
    addPerson,
    removePerson,
    movePerson,

    // 检测 & 报警
    checkBoundary,
    dismissAlarm,
    destroyGeofence,
  }
}

// ─── 工具函数 ────────────────────────────────────────

/** Haversine 公式计算两点间距离（米） */
function haversineDistance(
  [lng1, lat1]: [number, number],
  [lng2, lat2]: [number, number]
): number {
  const R = 6371000 // 地球半径（米）
  const dLat = ((lat2 - lat1) * Math.PI) / 180
  const dLng = ((lng2 - lng1) * Math.PI) / 180
  const a =
    Math.sin(dLat / 2) ** 2 +
    Math.cos((lat1 * Math.PI) / 180) *
      Math.cos((lat2 * Math.PI) / 180) *
      Math.sin(dLng / 2) ** 2
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  return R * c
}
