<template>
  <z-paging>
    <template #top>
      <navbar/>
      <view class="bg-white px-30rpx py-26rpx">
        <view class="flex items-center h-86rpx px-28rpx bg-#F6F7F9 rounded-20rpx">
          <wd-input v-model="mapSearchKeyword" :no-border="true" :placeholder="t('common.placeholder.pleaseEnter')"
                    custom-class="!w-full !bg-transparent" placeholder-class="text-#9B9CA0 text-28rpx">
            <template #prefix>
              <view class="w-12rpx h-12rpx rounded-50% bg-#F97C34"></view>
            </template>
          </wd-input>
        </view>

        <view class="" @click="handleUseLocation">
          <view class="text-32rpx text-#333 font-500 my-30rpx">{{ t('common.useMyCurrentLocation') }}</view>
          <view class="text-28rpx text-#333 font-500 flex items-center pb-20rpx pl-24rpx">
            <view class="i-carbon:location-current text-32rpx mr-14rpx mt-4rpx"></view>
            {{ t('common.useCurrentLocation') }}
          </view>
        </view>
      </view>
    </template>
    <view class="bg-#f5f5f5">
      <view class="px-22rpx py-20rpx">
        <view v-if="logicStore.searchLoading" class="center py-100rpx text-28rpx text-#9B9CA0">
          Loading...
        </view>

        <template v-else-if="placesLength > 0">
          <view class="rounded-36rpx bg-white">
            <view
              v-for="(item, index) in logicStore.placesList"
              :key="(item as any).id || index"
              :class="[index === logicStore.placesList.length - 1 ? '' : 'border-bottom']"
              class="px-22rpx pb-30rpx pt-34rpx"
              @click="handleClickLocation(item as AddressPlaceItem)"
            >
              <view class="text-#000 text-26rpx font-bold">{{ (item as any).displayName }}</view>
              <view class="text-#9B9CA0 text-24rpx flex-center-sb">
                <view>{{ (item as any).formattedAddress }}</view>
              </view>
            </view>
          </view>
        </template>

        <view v-else-if="hasSearched" class="center py-100rpx">
          <image class="w-250rpx h-250rpx" src="@img/chef/100.png"></image>
        </view>
      </view>
    </view>
  </z-paging>
</template>
<script lang="ts" setup>
import Config from "@/config";
import {useLogicStore} from "@/pages-user/store/logic";
import {useUserStore} from "@/store";
import {debounce} from "throttle-debounce";

const {t, locale} = useI18n();
const userStore = useUserStore()
const logicStore = useLogicStore()

export interface AddressPlaceItem {
  id: string
  displayName: string
  formattedAddress: string
  location: { lat: number; lng: number } | null
}

let openerEventChannel: any = null
onLoad(() => {
  const pages = getCurrentPages() as any[]
  const page = pages[pages.length - 1]
  openerEventChannel = page?.getOpenerEventChannel?.() || null
})

onMounted(() => {
  logicStore.clearPlacesList()
})

const placesLength = computed(() => logicStore.placesList.length)
const mapSearchKeyword = ref<string>('')
const hasSearched = ref(false)

watch(
  () => logicStore.searchLoading,
  (loading) => {
    if (loading) {
      uni.showLoading({ title: 'Loading...', mask: true })
    } else {
      uni.hideLoading()
    }
  },
  { immediate: true },
)

function resolveLanguageCode() {
  if (locale.value === 'zh-Hans') return 'zh-CN'
  if (locale.value === 'en') return 'en'
  return String(locale.value || 'en')
}

function resolveRegionCode() {
  return locale.value === 'zh-Hans' ? 'CN' : 'US'
}

function resolveBiasCenter() {
  const lat = Number(userStore.location.latitude)
  const lng = Number(userStore.location.longitude)
  if (Number.isFinite(lat) && Number.isFinite(lng) && (lat !== 0 || lng !== 0)) {
    return { latitude: lat, longitude: lng }
  }
  if (locale.value === 'zh-Hans') {
    return { latitude: 39.9042, longitude: 116.4074 }
  }
  return { latitude: 38.8977, longitude: -77.0365 }
}

function parsePlacesApiPlace(place: any): AddressPlaceItem | null {
  if (!place) return null

  const lat = place.location?.latitude
  const lng = place.location?.longitude
  const formattedAddress = String(place.formattedAddress || '').trim()
  const displayName = String(
    typeof place.displayName === 'string'
      ? place.displayName
      : place.displayName?.text || formattedAddress,
  ).trim()

  if (!displayName && !formattedAddress) return null

  return {
    id: String(place.id || ''),
    displayName: displayName || formattedAddress,
    formattedAddress,
    location:
      Number.isFinite(Number(lat)) && Number.isFinite(Number(lng))
        ? { lat: Number(lat), lng: Number(lng) }
        : null,
  }
}

function parseGeocodeResult(result: any): AddressPlaceItem | null {
  if (!result) return null

  const formattedAddress = String(result.formatted_address || '').trim()
  const lat = result.geometry?.location?.lat
  const lng = result.geometry?.location?.lng
  const displayName =
    formattedAddress.split(',')[0]?.trim() || formattedAddress

  if (!formattedAddress) return null

  return {
    id: String(result.place_id || ''),
    displayName,
    formattedAddress,
    location:
      Number.isFinite(Number(lat)) && Number.isFinite(Number(lng))
        ? { lat: Number(lat), lng: Number(lng) }
        : null,
  }
}

function requestJson<T = any>(options: UniApp.RequestOptions) {
  return new Promise<{ statusCode: number; data: T }>((resolve, reject) => {
    uni.request({
      timeout: 10000,
      ...options,
      success: (res) => resolve(res as any),
      fail: reject,
    })
  })
}

async function searchByPlacesTextSearch(keyword: string) {
  const languageCode = resolveLanguageCode()
  const regionCode = resolveRegionCode()
  const center = resolveBiasCenter()

  const res = await requestJson<{ places?: any[]; error?: any }>({
    url: 'https://places.googleapis.com/v1/places:searchText',
    method: 'POST',
    header: {
      'Content-Type': 'application/json',
      'X-Goog-Api-Key': Config.googleMapKey,
      'X-Goog-FieldMask': 'places.id,places.displayName,places.formattedAddress,places.location',
    },
    data: {
      textQuery: keyword,
      languageCode,
      regionCode,
      pageSize: 20,
      locationBias: {
        circle: {
          center,
          radius: 50000,
        },
      },
    },
  })

  if (res.statusCode !== 200) {
    const message = (res.data as any)?.error?.message || `HTTP ${res.statusCode}`
    throw new Error(message)
  }

  const places = Array.isArray(res.data?.places) ? res.data.places : []
  return places.map(parsePlacesApiPlace).filter(Boolean) as AddressPlaceItem[]
}

async function searchByGeocodeFallback(keyword: string) {
  const languageCode = resolveLanguageCode()
  const regionCode = resolveRegionCode()
  const query = encodeURIComponent(keyword)
  const url =
    `https://maps.googleapis.com/maps/api/geocode/json?address=${query}` +
    `&key=${Config.googleMapKey}&language=${languageCode}&region=${regionCode}`

  const res = await requestJson<{ results?: any[]; status?: string }>({
    url,
    method: 'GET',
  })

  if (res.statusCode !== 200 || res.data?.status !== 'OK') {
    return []
  }

  const results = Array.isArray(res.data.results) ? res.data.results : []
  return results.map(parseGeocodeResult).filter(Boolean) as AddressPlaceItem[]
}

async function searchPlaces(keyword: string) {
  logicStore.searchLoading = true
  hasSearched.value = true

  try {
    let list = await searchByPlacesTextSearch(keyword)

    if (list.length === 0) {
      list = await searchByGeocodeFallback(keyword)
    }

    logicStore.setPlacesList(list)
  } catch (error) {
    console.error('地址搜索失败', error)
    try {
      const fallback = await searchByGeocodeFallback(keyword)
      logicStore.setPlacesList(fallback)
    } catch (fallbackError) {
      console.error('Geocode 回退失败', fallbackError)
      logicStore.setPlacesList([])
    }
  } finally {
    logicStore.searchLoading = false
  }
}

const debouncedSearch = debounce(300, (keyword: string) => {
  void searchPlaces(keyword)
})

watch(mapSearchKeyword, (keyword) => {
  const text = String(keyword || '').trim()
  if (!text) {
    hasSearched.value = false
    logicStore.clearPlacesList()
    return
  }
  debouncedSearch(text)
})

function handleClickLocation(item: AddressPlaceItem) {
  openerEventChannel?.emit?.('chooseAddress', item)
  uni.navigateBack()
}

function handleUseLocation() {
  if (!userStore.location.longitude || !userStore.location.latitude) {
    uni.getLocation({
      isHighAccuracy: true,
      type: 'gcj02',
      geocode: true,
      success: (res) => {
        getCityName(res.latitude, res.longitude)
      },
      fail: () => {
        const settings = uni.getAppAuthorizeSetting()
        if (settings.locationAuthorized === 'denied') {
          uni.showToast({
            title: t('common.prompt.please-authorize-location-information'),
            icon: 'none',
          })
          setTimeout(() => {
            uni.openAppAuthorizeSetting()
          })
        }
      },
    })
  } else {
    openerEventChannel?.emit?.('chooseAddress', {
      displayName: userStore.location.location,
      formattedAddress: userStore.location.formattedAddress || '',
      location: {
        lng: userStore.location.longitude,
        lat: userStore.location.latitude,
      },
    })
    uni.navigateBack()
  }
}

function getCityName(latitude: number, longitude: number) {
  const languageCode = resolveLanguageCode()
  const url =
    `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}` +
    `&key=${Config.googleMapKey}&language=${languageCode}`

  uni.request({
    url,
    method: 'GET',
    timeout: 10000,
    success: (res: any) => {
      const results = res.data?.results || []

      if (!results.length) {
        return handleFail()
      }

      const addr = results[0]
      const components = addr.address_components || []

      const pickAddress = (types: string[]) => {
        return components.find((item: any) => item.types.some((type: string) => types.includes(type)))
      }

      const cityObj =
        pickAddress(['locality']) ||
        pickAddress(['administrative_area_level_2']) ||
        pickAddress(['administrative_area_level_1']) ||
        pickAddress(['political'])

      const cityName = cityObj?.long_name || null
      const formattedAddress = addr.formatted_address || cityName || ''

      if (!cityName) {
        return handleFail()
      }

      userStore.location = {
        location: cityName,
        formattedAddress,
        longitude,
        latitude,
      }

      openerEventChannel?.emit?.('chooseAddress', {
        displayName: cityName,
        formattedAddress,
        location: { lng: longitude, lat: latitude },
      })

      uni.navigateBack()
    },
    fail: () => handleFail(),
  })

  function handleFail() {
    uni.showToast({
      title: t('common.prompt.getLocationFailed'),
      icon: 'none',
    })
  }
}
</script>
<style>
page {
  background-color: #f5f5f5;
}
</style>
<style lang="scss" scoped>

</style>
