<!-- @format -->

<template>
  <div style="display: flex; width: 100%">
    <a-form-item-rest>
      <div class="rightBox">
        <div class="inputArea">
          <div style="margin-right: 10px">经度</div>
          <div class="longitude">
            <ns-input
              v-model:value="longLatTudeobj.longitude"
              type="number"
              class="input"
              placeholder="请输入经度"
              :disabled="viewOnly"
              @change="inputChange('longitude', $event)" /> </div
          ><div style="margin: 0 10px">纬度</div>
          <div class="latitude">
            <ns-input
              v-model:value="longLatTudeobj.latitude"
              type="number"
              class="input"
              placeholder="请输入纬度"
              :disabled="viewOnly"
              @change="inputChange('latitude', $event)" />
          </div>
        </div>
        <div class="inputSearch" style="margin: 15px 0 15px 0">
          <label style="margin-right: 10px">地址</label>
          <ns-input
            v-model:value="longLatTudeobj.address"
            class="inputAdress"
            :disabled="viewOnly"
            placeholder="请输入地址" />
          <ns-button type="primary" @click="onSearch" :disabled="viewOnly">查询</ns-button>
        </div>
        <div class="mapArea">
          <div id="map-container"></div>
          <div v-if="isShowResult" id="map-result" style="overflow: auto"></div>
        </div>
      </div>
    </a-form-item-rest>
  </div>
</template>
<script lang="ts">
  import { defineComponent, watch, ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue';
  import AMapLoader from '@amap/amap-jsapi-loader';
  import { shallowRef } from 'vue';
  import { isArray, isEqual, isEmpty } from 'lodash-es';

  export default defineComponent({
    name: 'NsMapV2',
    props: {
      defaultValue: {
        type: Array,
        default: () => {
          return [];
        },
      },
      viewOnly: {
        type: Boolean,
        default: false,
      },
      value: {
        type: Array,
        default: () => {
          return [];
        },
      },
      fieldMap: {
        type: Object || Array,
        default: () => {
          return [];
        },
      },
      formModel: {
        type: Object || Array,
      },
      //兼容v1写法
      longitude: {
        type: String,
        default: '',
      },
      latitude: {
        type: String,
        default: '',
      },
      defaultAddress: {
        type: String,
        default: '',
      },
      //兼容v1写法end
    },
    emits: ['change', 'updata:longLat'],
    setup(props, { emit }) {
      let map: Recordable;
      let geoc: any, localSearch: any, Amap: any;
      const isShowResult = ref(false);
      const hasload = ref(false);
      const longLatTudeobj = ref({
        longitude: '',
        latitude: '',
        address: '',
      });
      const delay = (time) => {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(map);
          }, time);
        });
      };
      const circleDelay = async () => {
        let res = await delay(100);
        if (res) {
          return res;
        } else {
          return circleDelay();
        }
      };

      //更新值
      const updateValue = async (event) => {
        if (!map) {
          //循环等待map初始化
          await circleDelay();
        }
        if (isArray(event)) {
          if (!event.length) return;
          longLatTudeobj.value['latitude'] = event[0] || '';
          longLatTudeobj.value['longitude'] = event[1] || '';
          longLatTudeobj.value['address'] = event[2] || '';

          if (longLatTudeobj.value['latitude'] && longLatTudeobj.value['longitude']) {
            map.clearMap();
            getAddressBylnglat(longLatTudeobj.value, (res) => {
              longLatTudeobj.value.address = res;
            });
            addMark({ position: [event[1], event[0]] });
            map.setFitView();
          }
        }
      };

      const resultPanelClick = (data: { [x: string]: string }) => {
        if (data && data['location']) {
          if (data['location']) {
            const location = data['location']; // 当前marker的经纬度信息
            longLatTudeobj.value.longitude = location['lng'].toFixed(6);
            longLatTudeobj.value.latitude = location['lat'].toFixed(6);
          }
          if (data['address']) {
            longLatTudeobj.value.address = data['address'];
          }
        }
      };
      //搜索
      const onSearch = () => {
        isShowResult.value = true;
        map.clearMap();
        if (!localSearch) return;
        localSearch.search(longLatTudeobj.value.address, (status: string, result: Recordable) => {
          if (status == 'complete' && result.info == 'OK') {
            const resultPoi = result['poiList']['pois'];
            if (resultPoi && resultPoi instanceof Array && resultPoi.length > 0) {
              const pois = result.poiList.pois;
              for (let i = 0; i < pois.length; i++) {
                const poi = pois[i];
                const marker = [];
                marker[i] = addMark({
                  position: poi.location, // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
                  title: poi.name,
                });
              }
              map.setFitView();
            }
          } else {
          }
        });
      };
      //初始化
      const initMap = async () => {
        AMapLoader.load({
          key: '2694972059c3b978de5d7e073efdfc64', // 申请好的Web端开发者Key,首次调用 load 时必填
          version: '1.4.15',
          plugins: ['AMap.Geocoder', 'AMap.PlaceSearch'],
        })
          .then((AMap) => {
            Amap = AMap;
            // 需要传入AMap ,否则方法无法调用
            map = new AMap.Map('map-container', {
              // center: [117.000923, 36.675807],
              resizeEnable: true,
              zoom: 12,
            });
            //精准搜索插件
            geoc = new AMap.Geocoder({
              city: '021',
            });

            //模糊匹配插件
            AMap.service('AMap.PlaceSearch', function () {
              // 回调函数
              // 实例化PlaceSearch
              localSearch = new AMap.PlaceSearch({
                pageSize: 5, // 每页显示多少行
                pageIndex: 1, // 显示的下标从那个开始
                type: '', // 类别,可以以|后面加其他类
                city: '021',
                panel: 'map-result', // 服务显示 的面板
                autoFitView: true,
              });
            });

            if (AMap.event) {
              // 搜索结果列表的点标记
              AMap.event.addListener(localSearch, 'listElementClick', (e) => {
                resultPanelClick(e['data']);
              });
              // 标记物点击
              AMap.event.addListener(localSearch, 'markerClick', (e) => {
                // console.log('搜索结果标记物点击');
                resultPanelClick(e['data']);
              });
            }
            //不可编辑状态
            if (!props.viewOnly) {
              map.on('click', (e) => {
                map.clearMap();
                getAddressByaddress(e, (res) => {
                  longLatTudeobj.value.address = res;
                  longLatTudeobj.value.latitude = e.lnglat['lat'].toFixed(6);
                  longLatTudeobj.value.longitude = e.lnglat['lng'].toFixed(6);
                });
                addMark({
                  position: e.lnglat,
                });
                map.setFitView();
              });
            }
          })
          .catch((e) => {});
      };
      //根据经纬度搜索
      const getAddressBylnglat = (event, callBack) => {
        geoc.getAddress(event.lnglat, (status, result) => {
          if (status == 'complete' && result.info == 'OK') {
            const addComp = result['regeocode']['addressComponent'];
            let address =
              addComp.province +
              addComp.city +
              addComp.district +
              addComp.street +
              addComp.streetNumber;
            callBack(address, result);
          }
        });
      };
      //根据关键字搜索
      const getAddressByaddress = (event, callBack) => {
        geoc.getAddress(event.lnglat, function (status, result) {
          if (status == 'complete' && result.info == 'OK') {
            const addComp = result['regeocode']['addressComponent'];
            let address =
              addComp.province +
              addComp.city +
              addComp.district +
              addComp.street +
              addComp.streetNumber;
            callBack(address, result);
          }
        });
      };
      //添加点标记
      const addMark = (data: Recordable) => {
        let marker = new Amap.Marker(data);
        map.add(marker);
      };
      onMounted(async () => {
        await initMap();
        if (props.value.length) {
          updateValue(props.value);
        }
        if (props.defaultValue.length) {
          updateValue(props.defaultValue);
        }
      });
      onBeforeUnmount(() => {
        map.destroy();
        // localSearch.render.markerList.clear();
        isShowResult.value = false;
      });

      watch(
        () => props.value,
        (newv, oldv) => {
          if (!isEqual(newv, oldv) && !isEqual(newv, longLatTudeobj.value)) {
            updateValue(newv);
          }
        },
        {
          immediate: true,
        },
      );

      watch(
        () => longLatTudeobj.value,
        (newv, oldv) => {
          if (newv) {
            emit('change', [newv['latitude'], newv['longitude'], newv['address']]);
          }
        },
        {
          deep: true,
        },
      );

      watch(
        () => props.formModel,
        (newv, oldv) => {
          if (!isEmpty(newv) && props.fieldMap.length && !hasload.value) {
            if (isArray(props.value) && !isEmpty(props.value)) {
              return;
            }
            let longitude = [];
            props.fieldMap.forEach((el, i) => {
              longitude[i] = newv[el];
            });
            updateValue(longitude);
            hasload.value = true;
          }
        },
        {
          immediate: true,
        },
      );

      //兼容老的处理方法
      watch(
        //
        () => [props.latitude, props.longitude, props.defaultAddress],
        //
        ([latitude, longitude, defaultAddress]) => {
          console.log(latitude, longitude, defaultAddress);
          if (latitude && longitude) {
            updateValue([latitude, longitude, defaultAddress]);
          }
        },
        {
          deep: true,
          immediate: true,
        },
      );

      return {
        map,
        isShowResult,
        longLatTudeobj,
        onSearch,
      };
    },
  });
</script>
<style lang="less" scoped>
  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    -webkit-appearance: none;
  }
  #map-container {
    height: 400px;
  }
  .leftBox,
  .rightBox {
    flex: 1;
  }
  .inputArea {
    display: flex;
    line-height: 30px;
  }
  .inputSearch {
    .inputAdress {
      width: 344px;
      margin-right: 10px;
    }
  }
</style>