<template>
  <div class="map-layout">
    <div class="search">
      <el-input
        v-model="keyword"
        :placeholder="`请输入${searchName}搜索`"
        class="input-with-select"
        @keydown.enter="searchHandler"
      >
        <template #prepend>
          <el-select v-model="searchType" style="width: 100px">
            <el-option
              :label="type.label"
              :value="type.value"
              v-for="type in searchTypes"
            />
          </el-select>
        </template>
      </el-input>

      <div
        class="latlng-result"
        v-if="searchType === 'latlng' && (mark || mark === null)"
        :class="{ success: mark }"
      >
        <template v-if="mark">
          <h3>经纬度定位成功</h3>
          <p>经度：{{ mark.lng }}</p>
          <p>纬度：{{ mark.lat }}</p>
        </template>
        <template v-else>
          <h3>经纬度定位失败</h3>
          <p>请输入正确的经纬度格式</p>
          <p>纬度,经度 （例如23.11766,113.28122）</p>
          <p>纬度范围：-90到90</p>
          <p>经度范围：-180到180</p>
        </template>
      </div>

      <div class="name-result" v-if="searchType === 'name' && options.length">
        <div
          class="address-item operate"
          v-for="option in options"
          :class="{ active: activeOption === option }"
          @click="clickOption(option)"
        >
          <span>{{ option.name }}</span>
          {{ option.address }}
        </div>
      </div>
    </div>

    <div class="map" ref="mapEle"></div>
    <div class="tiles-select" v-if="tileGroups.length > 1">
      <el-select v-model="groupIndex" style="width: 140px">
        <el-option :label="group.name" :value="ndx" v-for="(group, ndx) in tileGroups" />
      </el-select>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, ref, shallowRef, watch, watchEffect } from "vue";
import {
  getCurrentLatlng,
  LatLng,
  latlngStrTransform,
  useLMap,
  useOnlyMarker,
  useSetLTileLayers,
} from "./useLeaflet";
import { BasemapInfo, SearchResultItem, SelectMapImageProps } from "../index";
import html2canvas from "html2canvas";
import {
  ElInput,
  ElSelect,
  ElOption,
  ElDropdown,
  ElDropdownMenu,
  ElDropdownItem,
} from "element-plus";

const props = defineProps<SelectMapImageProps>();

const mapEle = shallowRef<HTMLDivElement>();
const lMap = useLMap(mapEle);
const setTileLayers = useSetLTileLayers(lMap);
const groupIndex = ref(props.activeGroupIndex || 0);
watchEffect(
  () => {
    if (groupIndex.value > props.tileGroups.length - 1) {
      groupIndex.value = 0;
    }
  },
  { flush: "sync" }
);
const tiles = computed(() => props.tileGroups[groupIndex.value].tiles);
watchEffect(() => setTileLayers(tiles.value));

const searchTypes = [
  { label: "经纬度", value: "latlng" },
  { label: "地址", value: "name" },
];
const searchType = ref(searchTypes[0].value as "latlng" | "name");
const searchName = computed(
  () => searchTypes.find((item) => item.value === searchType.value)!.label
);
const keyword = ref("");
const mark = useOnlyMarker(lMap, ref<LatLng | null>());
watch(searchType, () => {
  mark.value = undefined;
  keyword.value = "";
});

const options = ref<SearchResultItem[]>([]);
const activeOption = ref<SearchResultItem>();
const clickOption = (item: SearchResultItem) => {
  activeOption.value = item;
  mark.value = item.latlng;
  console.log(item);
};
let token = 0;
const searchHandler = async () => {
  const currentToken = ++token;
  if (searchType.value === "latlng") {
    mark.value = latlngStrTransform(keyword.value);
    return;
  }
  options.value = [];
  activeOption.value = undefined;

  if (!keyword.value) return;

  const result = await props.search(keyword.value, props.tileGroups[groupIndex.value].id);
  if (currentToken === token) {
    options.value = result;
  }
};

getCurrentLatlng().then((latlng) => {
  if (!keyword.value && mark.value === undefined && searchType.value === "latlng") {
    keyword.value = `${latlng.lat},${latlng.lng}`;
    searchHandler();
  }
});

const submit = async (): Promise<BasemapInfo> => {
  if (!lMap.value) {
    throw "地图未初始化";
  }

  const bound = lMap.value.getBounds();
  const southWest = bound.getSouthWest(); // 西南角
  const northEast = bound.getNorthEast(); // 东北角
  const width = lMap.value.distance(
    [southWest.lng, northEast.lat],
    [northEast.lng, northEast.lat]
  );
  const height = lMap.value.distance(
    [northEast.lng, southWest.lat],
    [northEast.lng, northEast.lat]
  );

  let blob: Blob;
  try {
    const canvas = await html2canvas(mapEle.value!, {
      useCORS: true, // 允许跨域图片（瓦片需支持 CORS）
      allowTaint: true, // 允许污染 Canvas（慎用）
      scale: 2, // 提高分辨率
      logging: false, // 关闭日志
    });

    blob = await new Promise<Blob>((resolve, reject) => {
      canvas.toBlob((blob) => {
        blob ? resolve(blob) : reject("截图失败");
      });
    });
  } catch (e) {
    throw "截图失败";
  }

  return {
    blob,
    size: { width, height },
  };
};

defineExpose({ submit });
</script>

<style lang="scss" scoped>
.map-layout {
  display: flex;
}

.search {
  margin-right: 24px;
  flex: 1;
}

.map {
  flex: 0 0 auto;
  height: 600px;
  width: 800px;
  position: relative;
}

.tiles-select {
  position: absolute;
  z-index: 9999;
  right: 30px;
  top: 70px;
}

.tiles-select-icon {
  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 1));
  // box-shadow: 0 0 3px #000;
}

.latlng-result {
  margin-top: 16px;
  border-radius: 2px;
  border: 1px solid #d9d9d9;
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  padding: 16px;

  p {
    font-size: 14px;
    color: #a7a7a7;
    line-height: 22px;
    min-width: 144px;
    text-align: left;
  }

  h3 {
    color: #f56c6c;
    font-weight: bold;
    font-size: 14px;
    margin-bottom: 8px;
  }

  &.success h3 {
    color: #67c23a;
  }
}

.name-result {
  margin-top: 10px;
  border-radius: 2px;
  max-height: 560px;
  overflow-y: auto;

  .address-item {
    padding: 16px 0px;
    display: flex;
    justify-content: center;
    flex-direction: column;
    color: rgba(0, 0, 0, 0.45);
    font-size: 14px;
    line-height: 22px;
    span {
      font-size: 14px;
      color: #000;
      margin-bottom: 4px;
    }
    cursor: pointer;

    &.active {
      background: var(--el-color-primary-light-9);
    }

    &:not(:last-child) {
      padding-bottom: 6px;
      border-bottom: 1px solid #d9d9d9;
    }
  }
}

.input-with-select {
  --el-fill-color-light: #ffffff;
}
</style>

<style lang="scss">
.leaflet-container {
  background: #fff;
}
</style>
