<template>
  <ElDialog
    v-model="dialogVisible"
    :title="t('store.deliveryZone.form.drawPolygonTitle')"
    width="70vw"
    top="5vh"
    :close-on-click-modal="false"
    :destroy-on-close="true"
    class="delivery-zone-polygon-dialog"
    @opened="handleOpened"
    @closed="handleClosed"
  >
    <div class="dialog-body">
      <ElAlert
        v-if="!apiKey"
        type="warning"
        :title="t('store.deliveryZone.form.mapKeyMissing')"
        show-icon
        class="mb-2"
      />

      <!-- Toolbar -->
      <div
        class="toolbar flex flex-wrap items-center justify-between gap-2 p-2 bg-gray-50 rounded border border-gray-200"
      >
        <div class="flex items-center gap-2">
          <ElButton type="primary" plain size="small" :disabled="!canDraw" @click="setMode('draw')">
            {{ t('store.deliveryZone.form.drawPolygon') }}
          </ElButton>
          <ElButton plain size="small" :disabled="!canEdit" @click="setMode('edit')">
            {{ t('store.deliveryZone.form.editPolygon') }}
          </ElButton>
          <ElButton type="danger" plain size="small" :disabled="!hasGeometry" @click="handleClear">
            {{ t('store.deliveryZone.form.clearPolygon') }}
          </ElButton>
        </div>
        <div class="text-xs text-gray-500">
          <span v-if="currentMode === 'draw'"
            >{{ t('common.tips') }}: {{ t('store.deliveryZone.form.drawHint') }}</span
          >
          <span v-else-if="currentMode === 'edit'"
            >{{ t('common.tips') }}:
            {{ t('store.deliveryZone.form.editHint', 'Drag points to adjust area') }}</span
          >
        </div>
      </div>

      <!-- Map Container -->
      <div class="map-shell mt-2">
        <div v-if="apiKey" :id="mapContainerId" class="map-canvas"></div>
        <div v-else class="map-empty">
          <div class="text-sm text-gray-500">
            {{ t('store.deliveryZone.form.mapKeyMissingHint') }}
          </div>
        </div>
      </div>
    </div>

    <template #footer>
      <div class="flex justify-end gap-2">
        <ElButton @click="dialogVisible = false">{{ t('common.cancel') }}</ElButton>
        <ElButton type="primary" @click="handleApply">
          {{ t('common.confirm') }}
        </ElButton>
      </div>
    </template>
  </ElDialog>
</template>

<script setup lang="ts">
  import { computed, nextTick, ref, shallowRef } from 'vue'
  import { useI18n } from 'vue-i18n'
  import { ElAlert, ElButton, ElDialog, ElMessage } from 'element-plus'
  import { loadTencentMapScript } from '@/utils/tencent-map'

  defineOptions({ name: 'DeliveryZonePolygonDialog' })

  const props = withDefaults(
    defineProps<{
      modelValue: boolean
      geoJson?: string
      storeLocation?: {
        longitude?: number | null
        latitude?: number | null
      }
    }>(),
    {
      geoJson: ''
    }
  )

  const emit = defineEmits<{
    (event: 'update:modelValue', value: boolean): void
    (event: 'apply', value: string): void
  }>()

  const { t } = useI18n()

  // Config
  const apiKey = import.meta.env.VITE_TENCENT_MAP_KEY as string
  const mapContainerId = `dz-map-${Math.random().toString(36).slice(2, 8)}`
  const DEFAULT_CENTER = { lat: 39.909187, lng: 116.397451 } // Beijing

  // Refs
  const dialogVisible = computed({
    get: () => props.modelValue,
    set: (val) => emit('update:modelValue', val)
  })

  // Shallow refs for Map instances (Performance)
  const mapInstance = shallowRef<any>(null)
  const overlayInstance = shallowRef<any>(null)
  const editorInstance = shallowRef<any>(null)
  const tmapNamespace = shallowRef<any>(null)

  // State
  const currentMode = ref<'draw' | 'edit' | 'none'>('none')
  const hasGeometry = ref(false)

  const canDraw = computed(() => !hasGeometry.value && apiKey)
  const canEdit = computed(() => hasGeometry.value && apiKey)

  // --- Map Logic ---

  const initMap = async () => {
    if (!apiKey) return

    try {
      await loadTencentMapScript(apiKey)
      const TMap = (window as any).TMap
      tmapNamespace.value = TMap

      // 1. Init Map
      const centerLatLng = getInitialCenter(TMap)
      mapInstance.value = new TMap.Map(document.getElementById(mapContainerId), {
        center: centerLatLng,
        zoom: 14,
        pitch: 0,
        rotation: 0
      })

      // 2. Init MultiPolygon Overlay
      overlayInstance.value = new TMap.MultiPolygon({
        map: mapInstance.value,
        styles: {
          // Highlight style
          highlight: new TMap.PolygonStyle({
            color: 'rgba(59, 130, 246, 0.2)',
            borderColor: 'rgba(37, 99, 235, 1)',
            borderWidth: 2
          })
        },
        geometries: [] // Start empty, fill later
      })

      // 3. Init GeometryEditor
      initEditor()

      // 4. Load Initial Data
      loadInitialGeometry()

      // 5. Add Store Marker
      addStoreMarker(TMap)
    } catch (err) {
      console.error('Map Init Failed:', err)
      ElMessage.error(t('common.error.operationFailed'))
    }
  }

  const addStoreMarker = (TMap: any) => {
    if (!props.storeLocation?.latitude || !props.storeLocation?.longitude) return

    new TMap.MultiMarker({
      map: mapInstance.value,
      styles: {
        store: new TMap.MarkerStyle({
          width: 25,
          height: 35,
          anchor: { x: 12, y: 35 }
        })
      },
      geometries: [
        {
          id: 'store-location',
          styleId: 'store',
          position: new TMap.LatLng(props.storeLocation.latitude, props.storeLocation.longitude),
          content: t('store.detail.title')
        }
      ]
    })
  }

  const initEditor = () => {
    const TMap = tmapNamespace.value
    if (!mapInstance.value || !overlayInstance.value || !TMap) return

    // Create new editor
    editorInstance.value = new TMap.tools.GeometryEditor({
      map: mapInstance.value,
      overlayList: [
        {
          overlay: overlayInstance.value,
          id: 'polygon-group',
          selectedStyleId: 'highlight',
          drawingStyleId: 'highlight' // Style when drawing
        }
      ],
      actionMode: TMap.tools.constants.EDITOR_ACTION.DRAW,
      activeOverlayId: 'polygon-group',
      selectable: true,
      snappable: true // Allow snapping to points
    })

    // Bind Events
    editorInstance.value.on('draw_complete', onDrawComplete)
    editorInstance.value.on('adjust_complete', onAdjustComplete)
    editorInstance.value.on('delete_complete', onDeleteComplete)
  }

  const getInitialCenter = (TMap: any) => {
    if (props.storeLocation?.latitude && props.storeLocation?.longitude) {
      return new TMap.LatLng(props.storeLocation.latitude, props.storeLocation.longitude)
    }
    return new TMap.LatLng(DEFAULT_CENTER.lat, DEFAULT_CENTER.lng)
  }

  const loadInitialGeometry = () => {
    if (!props.geoJson || !props.geoJson.trim()) {
      hasGeometry.value = false
      localGeoJson.value = ''
      setMode('draw')
      return
    }

    try {
      const geoObj = JSON.parse(props.geoJson)
      const TMap = tmapNamespace.value
      let paths: any[] = []

      // Parse Standard GeoJSON Polygon
      // GeoJSON coords are [lng, lat], TMap needs LatLng
      const parseRing = (ring: number[][]) => {
        return ring.map((p) => new TMap.LatLng(p[1], p[0]))
      }

      if (geoObj.type === 'Polygon') {
        paths = geoObj.coordinates.map(parseRing)
      } else if (geoObj.type === 'MultiPolygon') {
        // Take the first polygon if multiple
        if (geoObj.coordinates && geoObj.coordinates.length > 0) {
          paths = geoObj.coordinates[0].map(parseRing)
        }
      }

      if (paths.length > 0) {
        // Add to overlay
        overlayInstance.value.add([
          {
            id: 'main-zone',
            styleId: 'highlight',
            paths: paths
          }
        ])

        // Adjust map view
        const bounds = new TMap.LatLngBounds()
        paths.forEach((ring: any[]) => {
          ring.forEach((p) => bounds.extend(p))
        })
        mapInstance.value.fitBounds(bounds, { padding: 50 })

        hasGeometry.value = true
        localGeoJson.value = props.geoJson // Sync initial value
        setMode('edit')
      } else {
        setMode('draw')
      }
    } catch (e) {
      console.warn('Failed to parse initial GeoJSON', e)
      setMode('draw')
    }
  }

  // --- Interaction ---

  const setMode = (mode: 'draw' | 'edit') => {
    if (!editorInstance.value || !tmapNamespace.value) return
    const TMap = tmapNamespace.value
    const Constants = TMap.tools.constants

    if (mode === 'draw') {
      editorInstance.value.setActionMode(Constants.EDITOR_ACTION.DRAW)
      currentMode.value = 'draw'
    } else {
      editorInstance.value.setActionMode(Constants.EDITOR_ACTION.INTERACT)
      currentMode.value = 'edit'
    }
  }

  const onDrawComplete = (geometry: any) => {
    hasGeometry.value = true
    syncData(geometry)
    setMode('edit')
  }

  const onAdjustComplete = (geometry: any) => {
    syncData(geometry)
  }

  const onDeleteComplete = () => {
    hasGeometry.value = false
    localGeoJson.value = ''
    setMode('draw')
  }

  const handleClear = () => {
    // 1. Destroy Editor first to detach from overlay
    if (editorInstance.value) {
      editorInstance.value.destroy()
      editorInstance.value = null
    }

    // 2. Clear Overlay
    if (overlayInstance.value) {
      overlayInstance.value.setGeometries([])
    }

    // 3. Reset State & UI
    hasGeometry.value = false
    localGeoJson.value = ''
    currentMode.value = 'draw'

    // 4. Re-init Editor (Fresh start)
    initEditor()
  }

  // --- Data Sync ---

  const localGeoJson = ref('')

  // Enhanced syncData to accept geometry directly from events to avoid overlay sync race conditions
  const syncData = (eventGeometry?: any) => {
    // 1. Try to get geometry from event or overlay
    let geometry = eventGeometry

    if (!geometry) {
      if (!overlayInstance.value) return

      const geometries = overlayInstance.value.getGeometries()
      if (geometries && geometries.length > 0) {
        geometry = geometries[0]
      }
    }

    // 2. If no geometry found anywhere, clear data
    if (!geometry) {
      localGeoJson.value = ''
      return
    }

    // 3. Process Geometry
    try {
      let rawPaths = geometry.paths

      // Robustness: Wrap single loop polygon into multi-loop structure
      if (rawPaths && rawPaths.length > 0 && rawPaths[0].getLat) {
        rawPaths = [rawPaths]
      }

      const coordinates = rawPaths.map((ring: any[]) => {
        const ringCoords = ring.map((p: any) => [p.getLng(), p.getLat()])
        // Ensure closed loop
        if (ringCoords.length > 0) {
          const first = ringCoords[0]
          const last = ringCoords[ringCoords.length - 1]
          if (first[0] !== last[0] || first[1] !== last[1]) {
            ringCoords.push(first)
          }
        }
        return ringCoords
      })

      const geoJsonObj = {
        type: 'Polygon',
        coordinates: coordinates
      }

      localGeoJson.value = JSON.stringify(geoJsonObj)
    } catch (e) {
      console.error('Data Sync Failed', e)
    }
  }

  // --- Submit ---

  const handleApply = () => {
    // Do NOT call syncData() here. It may overwrite valid event-based data with stale/empty overlay data.
    // relying on onDrawComplete/onAdjustComplete to keep localGeoJson up to date.
    emit('apply', localGeoJson.value)
    dialogVisible.value = false
  }

  // --- Lifecycle ---

  const handleOpened = async () => {
    await nextTick()
    initMap()
  }

  const handleClosed = () => {
    if (editorInstance.value) {
      editorInstance.value.destroy()
      editorInstance.value = null
    }
    if (mapInstance.value) {
      mapInstance.value.destroy()
      mapInstance.value = null
    }
    hasGeometry.value = false
    currentMode.value = 'none'
  }
</script>

<style scoped>
  .delivery-zone-polygon-dialog :deep(.el-dialog__body) {
    display: flex;
    flex-direction: column;
    height: 70vh;
    padding: 10px 20px;
  }

  .dialog-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    overflow: hidden;
  }

  .map-shell {
    position: relative;
    flex: 1;
    overflow: hidden;
    background: #f5f7fa;
    border: 1px solid var(--el-border-color);
    border-radius: 8px;
  }

  .map-canvas {
    width: 100%;
    height: 100%;
  }

  .map-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: #909399;
  }
</style>
