<template>
  <el-dialog :visible.sync="visible" :title="mergedTitle" width="80%" top="5vh" @close="handleClose"
    :close-on-click-modal="true">
    <div class="container">
      <!-- 顶部坐标显示 -->
      <div class="coordinate-info" v-if="selectedPoint.lng">
        <el-tag type="info">经度: {{ selectedPoint.lng || '' }}</el-tag>
        <el-tag type="info">纬度: {{ selectedPoint.lat || '' }}</el-tag>
        <el-tag>地址: {{ selectedPoint.address }}</el-tag>
      </div>

      <!-- 主体内容 -->
      <div class="content-wrapper">
        <!-- 左侧搜索面板 -->
        <div class="search-panel" v-if="mode !== 'detail'">
          <!-- 搜索框（存在bug——placeholder不生效+无法清除输入值, 自动补全效果消耗地图额度） -->
          <!-- 这个第一次自动补全的list并不打点，选择了后打点，相当于选了2次 -->
          <div v-if="searchType == 'searchBox'">
            <!-- 通过v-if切换清除输入的值（没用暴露属性清除） -->
            <el-amap-search-box v-if="searchBoxIsShow" class="search-box" ref="searchBox" :search-option="searchOption"
              :on-search-result="onSearchResult">
            </el-amap-search-box>
          </div>

          <!-- 手写搜索框【keyup.enter支持enter回车事件】节约额度 -->
          <div v-else class="custom-search-box">
            <el-input v-model="searchKeyword" size="medium" placeholder="请输入地址进行搜索" @keyup.enter.native="handleSearch"
              clearable>
              <i slot="prefix" class="el-input__icon el-icon-search"></i>
            </el-input>
            <el-button type="primary" @click="handleSearch">搜索</el-button>
          </div>

          <!-- 搜索结果列表 -->
          <div class="search-results" v-if="searchResults.length > 0">
            <div v-for="(item, index) in searchResults" :key="index" @click="selectSearchResult(item, index)"
              :class="index === searchResultIdx ? 'result-item-active' : ''" class="result-item">
              <div class="result-title">{{ item.name }}</div>
              <div class="result-address">{{ item.address }}</div>
            </div>
          </div>
        </div>

        <!-- 地图区域 -->
        <div class="map-wrapper">
          <el-amap ref="map" :amap-manager="amapManager" :vid="'map-point-picker-dialog'" :zoom="mergedMapConfig.zoom"
            :zooms="mergedMapConfig.zooms" :center="mergedMapConfig.center" :mapStyle="mergedMapConfig.mapStyle"
            :features="mergedMapConfig.features" :detailMode="mergedMapConfig.detailMode" :pitch="mergedMapConfig.pitch"
            :events="mapEvents">
          </el-amap>
        </div>
      </div>

      <!-- 底部操作按钮 -->
      <span slot="footer" class="dialog-footer" v-if="mode !== 'detail'">
        <el-button @click="handleClose">取 消</el-button>
        <el-button type="primary" @click="handleConfirm" :disabled="!selectedPoint.lng">确 定</el-button>
      </span>
    </div>
  </el-dialog>
</template>

<script>
/* *
 * MapPointPickerDialog 是一个打开弹框地图选点/显示组件, 弹框状态支持v-model和.sync修饰符
 *
 * 搜索模式：
 * - searchBox: 默认，使用el-amap-search-box组件进行搜索
 * - custom: 自定义实现搜索功能，进行了节约额度的处理
 *
 * 使用示例：
  <!-- kebab-case 风格 -->
  <map-point-picker-dialog 
    :visible.sync="visible" 
    :mode="mode" 
    :in-point="inPoint" 
    @confirm="handlePointMapConfirm">
  </map-point-picker-dialog>

  <!-- kebab-case 风格 -->
  <mapPointPickerDialog 
    :v-model="visible" 
    :mode="mode" 
    :inPoint="inPoint" 
    @confirm="handlePointMapConfirm">
  </mapPointPickerDialog>
 */

import { AMapManager, lazyAMapApiLoaderInstance } from 'vue-amap'
const amapManager = new AMapManager()

export default {
  name: 'MapPointPickerDialog',
  // 自定义v-mode的属性使得和.sync的属性一致
  model: {
    prop: 'visible',
    event: 'update:visible'
  },
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    mode: {
      type: String, // 'add' 新增, 'edit' 编辑, 'detail' 查看
      default: 'add'
    },
    // 传入的点（如有传入：lng lat address 必传）
    inPoint: {
      type: Object,
      default: () => ({})
    },
    searchType: {
      type: String, // 【'searchBox'————el-amap-search-box组件, 'custom'/或其他——自定义实现】
      default: 'searchBox'
    },
    // 地图配置
    mapConfig: {
      type: Object,
      default: () => ({})
    },
  },
  data() {
    const self = this
    return {
      title: '',
      amapManager,
      map: null, // 地图实例
      geocoder: null, // 地址逆解析
      autocomplete: null, // 输入提示(搜索)
      marker: null,
      selectedPoint: {
        lng: null,
        lat: null,
        address: ''
      },
      // 搜索相关
      searchKeyword: '',
      searchOption: {
        city: '西安市',
        citylimit: false
      },
      searchResults: [],
      searchResultIdx: -1, // 当前选中的搜索结果索引
      searchBoxIsShow: false, // 搜索框是否显示（为了清除组件数据）
      // 默认配置
      defaultMapConfig: {
        zoom: 15,
        zooms: [3, 18],
        center: [108.95, 34.25],
        mapStyle: 'normal', // normal  dark  light  fresh ——— 浅蓝 
        // 地图显示要素控制
        features: [
          'bg',  // 地图底图/背景/陆地
          'road', // 道路
          'point', // 兴趣点/POI
          'building' // 建筑物/3D楼块
        ],
        detailMode: '2D',
        pitch: 0
      },
      // 插件推荐用new AMap.Geocoder()这种原生SDK方式引入方便配置属性，不采用vue-amap的引入方式
      // 地图事件 lazyAMapApiLoaderInstance 是一个延迟加载高德地图 API 的工具（不是加载静态资源），确保地图资源按需加载
      mapEvents: {
        init: (map) => {
          lazyAMapApiLoaderInstance.load().then(() => {
            self.map = map
            self.initMapComponents(map)
          })
        }
      }
    }
  },
  computed: {
    // 提供默认，也支持$refs.title=xxx修改
    mergedTitle() {
      if (this.title) {
        return this.title
      }
      const titles = {
        add: '选择位置',
        edit: '编辑位置',
        detail: '查看位置'
      }
      return titles[this.mode] || '选择位置'
    },
    // 组件默认 -> 地图默认 -> 已选中点的默认 {lng, lat, address, ...}
    mergedMapConfig() {
      if (this.mode === 'add') {
        return {
          ...this.defaultMapConfig,
          ...this.mapConfig
        }
      }
      // 编辑/查看模式尝试使用传入的坐标
      const lng = this.inPoint?.lng || this.inPoint?.longitude
      const lat = this.inPoint?.lat || this.inPoint?.latitude

      // 如果有有效坐标，则设置为中心点
      if (lng && lat) {
        return {
          ...this.defaultMapConfig,
          ...this.mapConfig,
          center: [lng, lat]
        }
      }
      // 否则使用默认配置
      return {
        ...this.defaultMapConfig,
        ...this.mapConfig
      }
    }
  },
  watch: {
    visible(newVal) {
      if (newVal) {
        // 延时执行，等待地图加载完成
        setTimeout(() => {
          this.updateMapOverlay()
        }, 200)
        this.searchBoxIsShow = true
      } else {
        this.searchKeyword = ''
        this.searchResults = []
        this.searchResultIdx = -1
        this.searchBoxIsShow = false
      }
    }
  },
  methods: {
    // 负责初始化地图组件和插件
    initMapComponents(map) {
      // 绑定点击事件（新增和编辑模式）
      if (this.mode !== 'detail') {
        map.on('click', this.onMapClick)
      }

      this.geocoder = new AMap.Geocoder({
        city: "全国",
        radius: 1000,
        extensions: "base",
        batch: false,
        roadlevel: 0
      })

      this.autocomplete = new AMap.Autocomplete(this.searchOption)
    },
    updateMapOverlay() {
      const map = this.amapManager.getMap()
      if (!map) return

      map.setCenter(this.mergedMapConfig.center)
      map.setZoom(this.mergedMapConfig.zoom)

      if ((this.mode === 'edit' || this.mode === 'detail') && this.inPoint.lng && this.inPoint.lat) {
        this.selectedPoint = { ...this.inPoint }
        // 做了冗余处理，避免编辑详情点不显示
        if (!this.marker) {
          this.marker = new AMap.Marker({
            map: map,
            icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_rs.png',
            position: [this.inPoint.lng, this.inPoint.lat],
            draggable: this.mode === 'edit',
            cursor: this.mode === 'edit' ? 'move' : 'default',
          })

          if (this.mode === 'edit') {
            this.marker.on('dragend', this.onMarkerDragEnd)
          }
        } else {
          // 更新已有marker的位置和属性
          this.marker.setPosition([this.inPoint.lng, this.inPoint.lat])
          this.marker.setDraggable(this.mode === 'edit')
          this.marker.setCursor(this.mode === 'edit' ? 'move' : 'default')
        }
      } else if (this.mode === 'add') {
        // 新增模式，清空状态
        this.clearMarker()
        this.selectedPoint = {
          lng: null,
          lat: null,
          address: ''
        }
      }
    },
    onMapClick(e) {
      if (this.mode === 'detail') return;
      const lnglat = e.lnglat;
      if (this.mode === 'add') {
        // 第一次点击创建marker
        if (!this.marker) {
          this.marker = new AMap.Marker({
            map: this.amapManager.getMap(),
            icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_rs.png',
            position: [lnglat.lng, lnglat.lat],
            draggable: true,
            cursor: 'move',
          });
          // 绑定拖拽事件
          this.marker.on('dragend', this.onMarkerDragEnd);
        }
        // 后续点击更新位置
        this.marker.setPosition([lnglat.lng, lnglat.lat]);
      } else if (this.mode === 'edit' && this.marker) {
        // 移动已有marker
        this.marker.setPosition([lnglat.lng, lnglat.lat]);
      }

      this.selectedPoint.lng = lnglat.lng;
      this.selectedPoint.lat = lnglat.lat;
      this.getAddressByLngLat(lnglat.lng, lnglat.lat);
    },
    onMarkerDragEnd(e) {
      const lnglat = e.lnglat;
      this.selectedPoint.lng = lnglat.lng;
      this.selectedPoint.lat = lnglat.lat;
      this.getAddressByLngLat(lnglat.lng, lnglat.lat);
    },
    getAddressByLngLat(lng, lat) {
      if (this.geocoder) {
        this.geocoder.getAddress([lng, lat], (status, result) => {
          if (status === 'complete' && result.regeocode) {
            this.selectedPoint.address = result.regeocode.formattedAddress
          } else {
            this.selectedPoint.address = '获取地址失败'
          }
        })
      }
    },
    clearMarker() {
      if (this.marker) {
        this.marker.setMap(null);
        this.marker = null;
      }
      this.selectedPoint = {
        lng: null,
        lat: null,
        address: ''
      }
    },
    // el-amap-search-box搜索结果处理
    onSearchResult(pois) {
      this.searchResults = pois

      // 如果有搜索结果，将地图中心移动到第一个结果位置（此时没打点不存在显示所有覆盖物）
      if (pois.length > 0 && this.mode !== 'detail') {
        const firstResult = pois[0]
        const map = this.amapManager.getMap()
        if (map && firstResult.location) {
          map.setCenter([firstResult.location.lng, firstResult.location.lat])
        }
      }
    },
    // 自定义搜索处理
    async handleSearch() {
      if (!this.searchKeyword.trim()) {
        return
      }
      try {
        const result = await new Promise((resolve, reject) => {
          this.autocomplete.search(this.searchKeyword, (status, result) => {
            if (status === 'complete') {
              resolve(result)
            } else {
              reject(new Error('搜索失败'))
            }
          })
        })
        // 过滤下没经纬度, 地址显示"[]"" 的数据
        this.searchResults = (Array.isArray(result.tips) ? result.tips : [])
          .filter(item =>
            item.location &&
            typeof item.address === 'string' &&
            item.address.trim().length > 0
          );
      } catch (error) {
        console.error('搜索失败:', error)
        this.searchResults = []
      }
    },
    // 选择搜索结果
    selectSearchResult(item, idx) {
      const map = this.amapManager.getMap()
      if (!map || !item.location) return

      map.setCenter([item.location.lng, item.location.lat])

      if (this.mode === 'add') {
        if (!this.marker) {
          this.marker = new AMap.Marker({
            map: map,
            icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_rs.png',
            position: [item.location.lng, item.location.lat],
            draggable: true,
            cursor: 'move',
          })
          this.marker.on('dragend', this.onMarkerDragEnd)
        } else {
          this.marker.setPosition([item.location.lng, item.location.lat])
        }
      } else if (this.mode === 'edit' && this.marker) {
        // 编辑模式下更新marker位置
        this.marker.setPosition([item.location.lng, item.location.lat])
      }

      this.searchResultIdx = idx
      this.selectedPoint = {
        lng: item.location.lng,
        lat: item.location.lat,
        address: item.address || item.name
      }
    },
    // 需要更新外层visible属性（外层必须用v-model或sync绑定）
    handleClose() {
      this.$emit('update:visible', false);
      this.searchKeyword = ''
      this.searchResults = []
    },
    handleConfirm() {
      if (this.selectedPoint.lng && this.selectedPoint.lat) {
        this.$emit('confirm', { ...this.selectedPoint })
      }
    },
  },
}
</script>

<style scoped>
.container {
  margin-top: -20px;
  height: calc(100vh - 150px);
  display: flex;
  flex-direction: column;
}

.coordinate-info {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
}

.content-wrapper {
  flex: 1;
  display: flex;
  gap: 16px;
}

.search-panel {
  width: 300px;
  padding: 16px;
  border: 1px solid #ebebeb;
  border-radius: 4px;
  background-color: #f5f5f5f5;

  .search-box {
    width: 100%;
  }

  .custom-search-box {
    display: flex;
    gap: 8px;

    ::v-deep .el-input {
      flex: 1;
    }

    ::v-deep .el-input__inner {
      border-radius: 4px;
    }
  }

  .search-results {
    overflow-y: auto;
    height: calc(100vh - 300px);
    padding-top: 12px;

    .result-item {
      padding: 8px 0 8px 8px;
      border-bottom: 1px solid #9999994d;
      cursor: pointer;
      text-align: left;

      .result-title {
        color: #333;
        font-size: 14px;
        font-weight: bold;
      }

      .result-address {
        color: #999;
        font-size: 12px;
        margin-top: 3px;
      }
    }

    /* 激活样式 */
    .result-item-active {
      background: #999;
      border-radius: 4px;

      .result-title,
      .result-address {
        color: #fff;
      }
    }
  }
}

/* 地图占据剩余空间 */
.map-wrapper {
  flex: 1;
  position: relative;
  border: 1px solid #ebebeb;
  border-radius: 4px;
  overflow: hidden;
}

.dialog-footer {
  text-align: center;
  margin-top: 20px;
}
</style>