<script setup lang="ts">
import type { LngLatTuple } from '../composables/delivery-page/geojson';

/**
 * 文件职责：配送区域地图绘制弹窗。
 * 1. 使用腾讯地图 GeometryEditor 提供标准的多边形绘制交互。
 * 2. 每个区域仅保留一块独立多边形，确认后回传 GeoJSON。
 */
import {
  computed,
  nextTick,
  onBeforeUnmount,
  ref,
  shallowRef,
  watch,
} from 'vue';

import { Alert, Button, message, Modal, Space } from 'ant-design-vue';

import {
  parsePolygonGeoJson,
  stringifyPolygonGeoJson,
} from '../composables/delivery-page/geojson';
import { geocodeAddressToLngLat } from '../composables/useTencentGeocoder';
import { loadTencentMapSdk } from '../composables/useTencentMapLoader';

interface Props {
  fallbackCityText: string;
  initialCenterAddress: string;
  initialCenterLatitude: null | number;
  initialCenterLongitude: null | number;
  initialGeoJson: string;
  open: boolean;
  zoneColor: string;
}

type LatLngLiteral = { lat: number; lng: number };

const props = defineProps<Props>();

const emit = defineEmits<{
  (event: 'confirm', geoJson: string): void;
  (event: 'update:open', value: boolean): void;
}>();

const DEFAULT_CENTER: LngLatTuple = [104.195_397, 35.861_66];
const MAP_MODAL_Z_INDEX = 10_000;
const MAP_DEBUG_PREFIX = '[TenantUI-DeliveryMap]';

const mapContainerRef = ref<HTMLDivElement | null>(null);
const mapInstance = shallowRef<any>(null);
const polygonLayer = shallowRef<any>(null);
const geometryEditor = shallowRef<any>(null);

const isMapLoading = ref(false);
const mapError = ref('');
const isDrawing = ref(false);
const polygonCount = ref(0);
const latestGeoJson = ref('');

const hasPolygon = computed(() => polygonCount.value > 0);
const canStartDrawing = computed(
  () =>
    !isMapLoading.value &&
    !mapError.value &&
    !!mapInstance.value &&
    !!geometryEditor.value,
);

function logMapDebug(step: string, payload?: unknown) {
  if (!import.meta.env.DEV) return;
  if (payload === undefined) {
    console.warn(MAP_DEBUG_PREFIX, step);
    return;
  }
  console.warn(MAP_DEBUG_PREFIX, step, payload);
}

function refreshMapViewport(center?: LngLatTuple) {
  const TMap = window.TMap;
  if (!mapInstance.value) return;

  // 弹窗二次打开时，地图容器尺寸可能在过渡动画中变化，手动触发重排避免灰底图。
  if (typeof mapInstance.value.resize === 'function') {
    mapInstance.value.resize();
  }

  if (
    center &&
    TMap?.LatLng &&
    typeof mapInstance.value.setCenter === 'function'
  ) {
    mapInstance.value.setCenter(new TMap.LatLng(center[1], center[0]));
  }

  forceMapRepaint(center);
}

function forceMapRepaint(center?: LngLatTuple) {
  const TMap = window.TMap;
  const map = mapInstance.value;
  if (!map) return;

  if (center && TMap?.LatLng && typeof map.panTo === 'function') {
    map.panTo(new TMap.LatLng(center[1], center[0]));
  }

  if (typeof map.getZoom === 'function' && typeof map.setZoom === 'function') {
    const currentZoom = Number(map.getZoom());
    if (Number.isFinite(currentZoom)) {
      const bumpedZoom = Math.min(20, Math.max(3, currentZoom + 1));
      map.setZoom(bumpedZoom);
      window.setTimeout(() => {
        if (!props.open || map !== mapInstance.value) return;
        map.setZoom(currentZoom);
      }, 100);
    }
  }
}

async function waitForMapContainerReady() {
  const maxAttempts = 20;
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
    await nextTick();
    const container = mapContainerRef.value;
    if (container && container.clientWidth > 0 && container.clientHeight > 0) {
      return container;
    }
    await new Promise((resolve) => window.setTimeout(resolve, 40));
  }

  return mapContainerRef.value;
}

function toLayerPoint([lng, lat]: LngLatTuple): any | LatLngLiteral {
  const TMap = window.TMap;
  if (TMap?.LatLng) {
    return new TMap.LatLng(lat, lng);
  }
  return { lat, lng };
}

function resolvePoint(point: any): LngLatTuple | null {
  if (!point) return null;
  const lng =
    typeof point.getLng === 'function' ? point.getLng() : Number(point.lng);
  const lat =
    typeof point.getLat === 'function' ? point.getLat() : Number(point.lat);
  if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null;
  if (lng < -180 || lng > 180 || lat < -90 || lat > 90) return null;
  return [lng, lat];
}

function normalizePolygon(points: LngLatTuple[]) {
  if (points.length < 3) return [] as LngLatTuple[];
  const normalized = points.map(([lng, lat]) => [lng, lat] as LngLatTuple);
  const first = normalized[0];
  const last = normalized[normalized.length - 1];
  if (!first || !last) return [] as LngLatTuple[];
  if (first[0] !== last[0] || first[1] !== last[1]) {
    normalized.push([first[0], first[1]]);
  }
  return normalized;
}

function unwrapPolygonPath(paths: any): any[] {
  if (!Array.isArray(paths) || paths.length === 0) return [];
  return Array.isArray(paths[0]) ? (paths[0] as any[]) : (paths as any[]);
}

function buildGeometry(points: LngLatTuple[], id = 'polygon-1') {
  return {
    id,
    styleId: 'highlight',
    // MultiPolygon 单个区域也使用“二维 paths（外环）”结构，避免编辑器回填后丢失图形。
    paths: [points.map((point) => toLayerPoint(point))],
  };
}

function setRawGeometries(geometries: any[]) {
  if (
    !polygonLayer.value ||
    typeof polygonLayer.value.setGeometries !== 'function'
  ) {
    return;
  }

  polygonLayer.value.setGeometries(geometries);
  polygonCount.value = geometries.length;
}

function setPolygonToLayer(points: LngLatTuple[] | null) {
  if (!points) {
    setRawGeometries([]);
    return;
  }

  const ring = normalizePolygon(points);
  if (ring.length < 4) {
    setRawGeometries([]);
    return;
  }

  setRawGeometries([buildGeometry(ring)]);
}

function getMapCenterFromGeoJson(raw: string): LngLatTuple | null {
  const parsed = parsePolygonGeoJson(raw);
  const firstPoint = parsed[0]?.[0];
  if (!firstPoint) return null;
  // 0,0 常见于后端空坐标默认值，作为无效点处理。
  if (firstPoint[0] === 0 && firstPoint[1] === 0) return null;
  return firstPoint ?? null;
}

function getMapCenterFromCoordinates() {
  const lng = Number(props.initialCenterLongitude);
  const lat = Number(props.initialCenterLatitude);
  if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null;
  if (lng < -180 || lng > 180 || lat < -90 || lat > 90) return null;
  // 0,0 常见于后端空坐标默认值，作为无效点处理。
  if (lng === 0 && lat === 0) return null;
  return [lng, lat] as LngLatTuple;
}

async function resolveInitialCenter() {
  const centerFromGeoJson = getMapCenterFromGeoJson(props.initialGeoJson);
  if (centerFromGeoJson) {
    return { center: centerFromGeoJson, shouldResolveAsync: false };
  }

  const centerFromCoordinates = getMapCenterFromCoordinates();
  if (centerFromCoordinates) {
    return { center: centerFromCoordinates, shouldResolveAsync: false };
  }

  // 优先保证地图首屏可见，地址编码异步纠偏中心点，避免白屏等待。
  return { center: DEFAULT_CENTER, shouldResolveAsync: true };
}

async function geocodeAddressWithTimeout(address: string, timeoutMs: number) {
  const timeoutPromise = new Promise<LngLatTuple | null>((resolve) => {
    window.setTimeout(() => resolve(null), timeoutMs);
  });

  return Promise.race([geocodeAddressToLngLat(address), timeoutPromise]);
}

async function resolveAsyncCenterByAddress() {
  const centerFromStoreAddress = await geocodeAddressWithTimeout(
    props.initialCenterAddress,
    1800,
  );
  if (centerFromStoreAddress) return centerFromStoreAddress;

  const centerFromMerchantCity = await geocodeAddressWithTimeout(
    props.fallbackCityText,
    1800,
  );
  if (centerFromMerchantCity) return centerFromMerchantCity;

  return null;
}

function createHighlightPolygonStyle(TMap: any) {
  return new TMap.PolygonStyle({
    color: 'rgba(24, 144, 255, 0.28)',
    showBorder: true,
    borderWidth: 2,
    borderColor: '#1d4ed8',
  });
}

function setEditorActionMode(mode: 'DRAW' | 'INTERACT') {
  const TMap = window.TMap;
  if (!TMap?.tools?.constants?.EDITOR_ACTION || !geometryEditor.value) return;

  const actionMode = TMap.tools.constants.EDITOR_ACTION[mode];
  if (actionMode === undefined) return;

  if (
    mode === 'DRAW' &&
    typeof geometryEditor.value.setActiveOverlay === 'function'
  ) {
    geometryEditor.value.setActiveOverlay('polygon-group');
  }

  geometryEditor.value.setActionMode(actionMode);
}

function geometryToPolygon(geometry: any) {
  const pathList = unwrapPolygonPath(geometry?.paths);
  if (!Array.isArray(pathList) || pathList.length < 3) return null;

  const points = pathList
    .map((point) => resolvePoint(point))
    .filter((point): point is LngLatTuple => !!point);
  const ring = normalizePolygon(points);
  if (ring.length < 4) return null;
  return ring;
}

function syncGeoJsonFromGeometry(eventGeometry?: any) {
  // 与 AdminUI 对齐：优先使用事件 geometry，避免依赖 overlay 的异步落盘时序。
  const fromEvent = geometryToPolygon(eventGeometry);

  let fromLayer: LngLatTuple[] | null = null;
  if (!fromEvent) {
    const layerGeometries =
      typeof polygonLayer.value?.getGeometries === 'function'
        ? polygonLayer.value.getGeometries()
        : polygonLayer.value?.geometries;
    const firstGeometry = Array.isArray(layerGeometries)
      ? layerGeometries[0]
      : null;
    fromLayer = geometryToPolygon(firstGeometry);
  }

  const polygon = fromEvent ?? fromLayer;
  if (!polygon) {
    latestGeoJson.value = '';
    polygonCount.value = 0;
    return false;
  }

  latestGeoJson.value = stringifyPolygonGeoJson([polygon]);
  polygonCount.value = 1;
  return true;
}

function onDrawComplete(geometry?: any) {
  const synced = syncGeoJsonFromGeometry(geometry);
  if (!synced && typeof window !== 'undefined') {
    // draw_complete 可能先于图层状态可读，延后一拍兜底读取。
    window.setTimeout(() => {
      const recovered = syncGeoJsonFromGeometry();
      if (!recovered) {
        message.warning('未识别到有效区域，请重新绘制');
        return;
      }
      isDrawing.value = false;
      setEditorActionMode('INTERACT');
    }, 0);
    return;
  }

  if (!synced) {
    message.warning('未识别到有效区域，请重新绘制');
    return;
  }

  isDrawing.value = false;
  setEditorActionMode('INTERACT');
}

function onAdjustComplete(geometry?: any) {
  void syncGeoJsonFromGeometry(geometry);
}

function onDeleteComplete() {
  latestGeoJson.value = '';
  polygonCount.value = 0;
  isDrawing.value = false;
  setEditorActionMode('INTERACT');
}

function destroyEditor() {
  if (
    geometryEditor.value &&
    typeof geometryEditor.value.destroy === 'function'
  ) {
    geometryEditor.value.destroy();
  }
  geometryEditor.value = null;
}

function destroyMapResources() {
  destroyEditor();

  if (polygonLayer.value && typeof polygonLayer.value.setMap === 'function') {
    polygonLayer.value.setMap(null);
  }
  polygonLayer.value = null;

  if (mapInstance.value && typeof mapInstance.value.destroy === 'function') {
    mapInstance.value.destroy();
  }
  mapInstance.value = null;
}

function createEditor() {
  const TMap = window.TMap;
  if (!TMap?.tools?.GeometryEditor || !mapInstance.value || !polygonLayer.value)
    return;

  destroyEditor();
  geometryEditor.value = new TMap.tools.GeometryEditor({
    map: mapInstance.value,
    overlayList: [
      {
        id: 'polygon-group',
        overlay: polygonLayer.value,
        selectedStyleId: 'highlight',
        drawingStyleId: 'highlight',
      },
    ],
    activeOverlayId: 'polygon-group',
    actionMode: TMap.tools.constants.EDITOR_ACTION.INTERACT,
    selectable: true,
    snappable: true,
  });

  geometryEditor.value.on('draw_complete', onDrawComplete);
  geometryEditor.value.on('adjust_complete', onAdjustComplete);
  geometryEditor.value.on('delete_complete', onDeleteComplete);
}

function fitMapToPolygon(points: LngLatTuple[]) {
  const TMap = window.TMap;
  if (
    !TMap?.LatLngBounds ||
    !mapInstance.value ||
    typeof mapInstance.value.fitBounds !== 'function'
  ) {
    return;
  }

  const ring = normalizePolygon(points);
  if (ring.length < 4) return;

  const bounds = new TMap.LatLngBounds();
  ring.forEach(([lng, lat]) => {
    bounds.extend(new TMap.LatLng(lat, lng));
  });
  mapInstance.value.fitBounds(bounds, { padding: 50 });
}

function loadInitialPolygon() {
  const initialPolygons = parsePolygonGeoJson(props.initialGeoJson);
  const first = initialPolygons[0];
  if (!first) {
    setRawGeometries([]);
    latestGeoJson.value = '';
    polygonCount.value = 0;
    return;
  }

  setPolygonToLayer(first);
  latestGeoJson.value = stringifyPolygonGeoJson([first]);
  polygonCount.value = 1;
  fitMapToPolygon(first);
}

async function ensureMapReady() {
  if (!props.open) return;
  mapError.value = '';
  isMapLoading.value = true;
  logMapDebug('ensureMapReady:start', { open: props.open });

  try {
    const TMap = await loadTencentMapSdk();
    logMapDebug('ensureMapReady:sdk-loaded', {
      hasMapClass: !!TMap?.Map,
      hasGeometryEditor: !!TMap?.tools?.GeometryEditor,
    });
    const container = await waitForMapContainerReady();
    if (!container) {
      throw new Error('地图容器尚未就绪，请关闭后重试');
    }
    logMapDebug('ensureMapReady:container-ready', {
      width: container.clientWidth,
      height: container.clientHeight,
    });

    const {
      center: [centerLng, centerLat],
      shouldResolveAsync,
    } = await resolveInitialCenter();
    logMapDebug('ensureMapReady:center-resolved', {
      centerLng,
      centerLat,
      shouldResolveAsync,
    });

    if (!mapInstance.value) {
      mapInstance.value = new TMap.Map(container, {
        center: new TMap.LatLng(centerLat, centerLng),
        zoom: 12,
        pitch: 0,
        rotation: 0,
      });
      logMapDebug('ensureMapReady:map-created');
    } else if (typeof mapInstance.value.setCenter === 'function') {
      mapInstance.value.setCenter(new TMap.LatLng(centerLat, centerLng));
      logMapDebug('ensureMapReady:map-recentered');
    }

    if (!polygonLayer.value) {
      polygonLayer.value = new TMap.MultiPolygon({
        map: mapInstance.value,
        styles: {
          highlight: createHighlightPolygonStyle(TMap),
        },
        geometries: [],
      });
      logMapDebug('ensureMapReady:polygon-layer-created');
    }

    if (!TMap.tools?.GeometryEditor) {
      throw new Error('腾讯地图绘图工具库未加载');
    }

    createEditor();
    logMapDebug('ensureMapReady:editor-created', {
      editorReady: !!geometryEditor.value,
    });
    loadInitialPolygon();
    setEditorActionMode('INTERACT');
    window.setTimeout(() => {
      refreshMapViewport([centerLng, centerLat]);
    }, 80);
    window.setTimeout(() => {
      refreshMapViewport([centerLng, centerLat]);
    }, 360);
    window.setTimeout(() => {
      refreshMapViewport([centerLng, centerLat]);
    }, 900);

    if (shouldResolveAsync) {
      void resolveAsyncCenterByAddress().then((asyncCenter) => {
        if (!props.open || !mapInstance.value || !asyncCenter) return;

        const [asyncLng, asyncLat] = asyncCenter;
        if (typeof mapInstance.value.setCenter === 'function') {
          mapInstance.value.setCenter(new TMap.LatLng(asyncLat, asyncLng));
        }
        refreshMapViewport(asyncCenter);
      });
    }
  } catch (error) {
    console.error('腾讯地图初始化失败', error);
    logMapDebug('ensureMapReady:failed', error);
    mapError.value =
      error instanceof Error ? error.message : '腾讯地图加载失败，请稍后重试';
  } finally {
    isMapLoading.value = false;
    logMapDebug('ensureMapReady:finished', {
      mapReady: !!mapInstance.value,
      editorReady: !!geometryEditor.value,
      mapError: mapError.value,
    });
  }
}

async function startDrawing() {
  logMapDebug('startDrawing:clicked', {
    mapError: mapError.value,
    isMapLoading: isMapLoading.value,
    hasMap: !!mapInstance.value,
    hasEditor: !!geometryEditor.value,
    polygonCount: polygonCount.value,
  });
  if (mapError.value) return;
  if (isMapLoading.value) {
    message.info('地图加载中，请稍后再试');
    return;
  }

  if (!mapInstance.value) {
    logMapDebug('startDrawing:ensureMapReady');
    await ensureMapReady();
  }

  if (!geometryEditor.value) {
    createEditor();
  }
  if (!geometryEditor.value) {
    message.error('绘图器尚未就绪，请稍后重试');
    logMapDebug('startDrawing:editor-not-ready');
    return;
  }

  if (polygonCount.value > 0) {
    setRawGeometries([]);
    latestGeoJson.value = '';
    polygonCount.value = 0;
  }
  setEditorActionMode('DRAW');
  isDrawing.value = true;
  message.info('请在地图上依次点击，双击完成区域');
  logMapDebug('startDrawing:entered-draw-mode');
}

function clearPolygon() {
  if (!geometryEditor.value) {
    createEditor();
  }

  setRawGeometries([]);
  latestGeoJson.value = '';
  polygonCount.value = 0;
  setEditorActionMode('INTERACT');
  isDrawing.value = false;
}

function handleConfirm() {
  if (!latestGeoJson.value) {
    syncGeoJsonFromGeometry();
  }
  if (!latestGeoJson.value) {
    message.error('请先绘制配送区域');
    return;
  }

  emit('confirm', latestGeoJson.value);
  emit('update:open', false);
}

function handleClose() {
  emit('update:open', false);
}

function getModalContainer(): HTMLElement {
  return document.body;
}

let openLifecycleToken = 0;

function scheduleViewportRefresh(token: number) {
  // 连续两次重排，兼容不同机器上的弹窗动画时机差异。
  window.setTimeout(() => {
    if (!props.open || token !== openLifecycleToken) return;
    refreshMapViewport();
  }, 80);
  window.setTimeout(() => {
    if (!props.open || token !== openLifecycleToken) return;
    refreshMapViewport();
  }, 260);
}

watch(
  () => props.open,
  async (open) => {
    const token = ++openLifecycleToken;
    logMapDebug('watch:open-changed', { open, token });
    if (!open) {
      isDrawing.value = false;
      latestGeoJson.value = '';
      polygonCount.value = 0;
      destroyMapResources();
      logMapDebug('watch:closed-resources-destroyed', { token });
      return;
    }

    await nextTick();
    if (!props.open || token !== openLifecycleToken) return;

    await ensureMapReady();
    if (!props.open || token !== openLifecycleToken) return;

    scheduleViewportRefresh(token);
    logMapDebug('watch:open-init-finished', { token });
  },
  { immediate: true },
);

onBeforeUnmount(() => {
  destroyMapResources();
});
</script>

<template>
  <Modal
    :open="props.open"
    title="绘制配送区域"
    width="980px"
    :mask-closable="false"
    :z-index="MAP_MODAL_Z_INDEX"
    :get-container="getModalContainer"
    :destroy-on-close="true"
    @cancel="handleClose"
  >
    <div class="delivery-map-modal">
      <div class="delivery-map-toolbar">
        <Space size="small" wrap>
          <Button
            size="small"
            type="primary"
            :disabled="!canStartDrawing"
            @click="startDrawing"
          >
            开始绘制
          </Button>
          <Button size="small" danger ghost @click="clearPolygon">清空</Button>
        </Space>
        <div class="delivery-map-status">
          <span
            class="delivery-map-status-pill"
            :class="{ drawing: isDrawing }"
          >
            {{ isDrawing ? '绘制中（双击结束）' : '已暂停' }}
          </span>
          <span class="delivery-map-status-text">
            已绘制 {{ polygonCount }} 块，单区域模式（新绘制会覆盖旧区域）
          </span>
        </div>
      </div>

      <Alert
        v-if="mapError"
        type="error"
        :message="mapError"
        show-icon
        class="delivery-map-alert"
      />

      <div
        ref="mapContainerRef"
        class="delivery-map-canvas"
        :class="{ loading: isMapLoading }"
      ></div>
    </div>

    <template #footer>
      <Button @click="handleClose">取消</Button>
      <Button type="primary" :disabled="!hasPolygon" @click="handleConfirm">
        确认使用该区域
      </Button>
    </template>
  </Modal>
</template>
