<script lang="ts" setup>
import type { ScrollViewOnScrollEvent } from '@uni-helper/uni-app-types'
import { computed, defineComponent, reactive, ref, watch } from 'vue'
import { CHANGE_EVENT, CLOSE_EVENT, PREFIX, SELECTED_EVENT, UPDATE_MODEL_EVENT, UPDATE_VISIBLE_EVENT } from '../_constants'
import { getMainClass } from '../_utils'
import requestAniFrame from '../_utils/raf'
import { useTranslate } from '../../locale'
import NutElevator from '../elevator/elevator.vue'
import NutIcon from '../icon/icon.vue'
import NutPopup from '../popup/popup.vue'
import { addressEmits, addressProps } from './address'
import type { AddressExistRegionData, AddressRegionData, CustomRegionData } from './type'

const props = defineProps(addressProps)
const emit = defineEmits(addressEmits)

const classes = computed(() => {
  return getMainClass(props, componentName)
})

const showPopup = ref(props.visible)
const privateType = ref(props.type)
const tabIndex = ref(0)
const prevTabIndex = ref(0)
const tabName = ref(['province', 'city', 'country', 'town'])
const scrollDis = ref([0, 0, 0, 0])
const scrollTop = ref(0)
const regionData = reactive<Array<AddressRegionData[]>>([])

const regionList = computed(() => {
  switch (tabIndex.value) {
    case 0:
      return props.province
    case 1:
      return props.city
    case 2:
      return props.country
    default:
      return props.town
  }
})

function transformData(data: AddressRegionData[]) {
  if (!Array.isArray(data))
    throw new TypeError('params muse be array.')

  if (!data.length)
    return []

  data.forEach((item: AddressRegionData) => {
    if (!item.title)
      console.warn('[NutUI] <Address> 请检查数组选项的 title 值是否有设置 ,title 为必填项 .')
  })

  const newData: CustomRegionData[] = []

  data = data.sort((a: AddressRegionData, b: AddressRegionData) => {
    return a.title.localeCompare(b.title)
  })

  data.forEach((item: AddressRegionData) => {
    const index = newData.findIndex((value: CustomRegionData) => value.title === item.title)
    if (index <= -1) {
      newData.push({
        title: item.title,
        list: ([] as any).concat(item),
      })
    }
    else {
      newData[index].list.push(item)
    }
  })

  return newData
}

const selectedRegion = ref<AddressRegionData[]>([])

let selectedExistAddress = reactive({}) // 当前选择的地址

const closeWay = ref<'self' | 'mask' | 'cross'>('self')

// 设置选中省市县
function initCustomSelected() {
  regionData[0] = props.province || []
  regionData[1] = props.city || []
  regionData[2] = props.country || []
  regionData[3] = props.town || []

  const defaultValue = props.modelValue
  const num = defaultValue.length
  if (num > 0) {
    tabIndex.value = num - 1
    if (regionList.value.length === 0) {
      tabIndex.value = 0
      return
    }
    for (let index = 0; index < num; index++) {
      const arr: AddressRegionData[] = regionData[index]
      selectedRegion.value[index] = arr.filter((item: AddressRegionData) => item.id === defaultValue[index])[0]
    }
    scrollTo()
  }
}

function getTabName(item: AddressRegionData | null, index: number) {
  if (item && item.name)
    return item.name
  if (tabIndex.value < index && item)
    return item.name

  else
    return props.columnsPlaceholder[index] || translate('select')
}

// 手动关闭 点击叉号(cross)，或者蒙层(mask)
function handClose(type = 'self') {
  closeWay.value = type === 'cross' ? 'cross' : 'self'

  showPopup.value = false
}

// 点击遮罩层关闭
function clickOverlay() {
  closeWay.value = 'mask'
}

// 切换下一级列表
function nextAreaList(item: AddressRegionData) {
  const tab = tabIndex.value
  prevTabIndex.value = tabIndex.value
  const callBackParams: {
    next?: string
    value?: AddressRegionData
    custom: string
  } = {
    custom: tabName.value[tab],
  }

  selectedRegion.value[tab] = item

  // 删除右边已选择数据
  selectedRegion.value.splice(tab + 1, selectedRegion.value.length - (tab + 1))

  callBackParams.value = item

  if (regionData[tab + 1]?.length > 0) {
    tabIndex.value = tab + 1

    callBackParams.next = tabName.value[tabIndex.value]

    scrollToTop()
  }
  else {
    handClose()
    emit(UPDATE_MODEL_EVENT)
  }
  emit(CHANGE_EVENT, callBackParams)
}
// 切换地区Tab
function changeRegionTab(item: AddressRegionData, index: number) {
  prevTabIndex.value = tabIndex.value
  if (getTabName(item, index)) {
    tabIndex.value = index
    scrollTo()
  }
}

function scrollChange(e: ScrollViewOnScrollEvent) {
  scrollDis.value[tabIndex.value] = e.detail.scrollTop
}

function scrollToTop() {
  // scrollTop 不会实时变更。当再次赋值时，scrollTop无变化时，不会触发滚动
  scrollTop.value += 1
  requestAniFrame(() => {
    setTimeout(() => {
      // 直接设置为0无效
      scrollTop.value = 0.01
    }, 100)
  })
}

function scrollTo() {
  // scrollTop 不会实时变更。当再次赋值时，scrollTop无变化时，不会触发滚动
  scrollTop.value += 1
  requestAniFrame(() => {
    setTimeout(() => {
      scrollTop.value = scrollDis.value[tabIndex.value]
    }, 10)
  })
}

// 选择现有地址
function selectedExist(item: AddressExistRegionData) {
  const copyExistAdd = props.existAddress
  let prevExistAdd: AddressExistRegionData = {} as AddressExistRegionData

  copyExistAdd.forEach((list: AddressExistRegionData) => {
    if (list && list.selectedAddress)
      prevExistAdd = list
    list.selectedAddress = false
  })

  item.selectedAddress = true

  selectedExistAddress = item

  emit(SELECTED_EVENT, prevExistAdd, item, copyExistAdd)

  handClose()
}
// 初始化
function initAddress() {
  selectedRegion.value = []
  tabIndex.value = 0
  scrollTo()
}

// 关闭
function close() {
  const data = {
    addressIdStr: '',
    addressStr: '',
    province: selectedRegion.value[0],
    city: selectedRegion.value[1],
    country: selectedRegion.value[2],
    town: selectedRegion.value[3],
  }

  const callBackParams = {
    data: {},
    type: privateType.value,
  }

  if (['custom', 'custom2'].includes(privateType.value)) {
    [0, 1, 2, 3].forEach((i) => {
      const item = selectedRegion.value[i]
      data.addressIdStr += `${i ? '_' : ''}${(item && item.id) || 0}`
      data.addressStr += (item && item.name) || ''
    })

    callBackParams.data = data
  }
  else {
    callBackParams.data = selectedExistAddress
  }

  initAddress()

  if (closeWay.value === 'self')
    emit(CLOSE_EVENT, callBackParams)
  else
    emit('closeMask', { closeWay: closeWay.value })

  emit(UPDATE_VISIBLE_EVENT, false)
}

// 选择其他地址
function switchModule() {
  const type = privateType.value
  privateType.value = type === 'exist' ? 'custom' : 'exist'
  initAddress()
  emit('switchModule', { type: privateType.value })
}

function handleElevatorItem(key: string, item: AddressRegionData) {
  nextAreaList(item)
}

watch(
  () => props.visible,
  (value) => {
    showPopup.value = value
  },
)

watch(
  () => showPopup.value,
  (value) => {
    if (value)
      initCustomSelected()
  },
)
</script>

<script lang="ts">
const componentName = `${PREFIX}-address`
const { translate } = useTranslate(componentName)

export default defineComponent({
  name: componentName,
  options: {
    virtualHost: true,
    addGlobalClass: true,
    styleIsolation: 'shared',
  },
})
</script>

<template>
  <NutPopup
    v-model:visible="showPopup"
    :z-index="zIndex"
    position="bottom"
    :lock-scroll="lockScroll"
    :round="round"
    :safe-area-inset-bottom="safeAreaInsetBottom"
    @close="close"
    @click-overlay="clickOverlay"
    @open="closeWay = 'self'"
  >
    <view :class="classes" :style="customStyle">
      <view class="nut-address__header">
        <view class="nut-address__header-back" @click="switchModule">
          <slot v-if="type === 'exist' && privateType === 'custom'" name="backIcon">
            <NutIcon name="left" size="14px" />
          </slot>
        </view>

        <view class="nut-address__header__title">
          {{
            privateType === 'custom'
              ? customAddressTitle || translate('selectRegion')
              : existAddressTitle || translate('deliveryTo')
          }}
        </view>

        <view class="nut-address__header-close" @click="handClose('cross')">
          <slot name="closeIcon">
            <NutIcon name="close" custom-color="#cccccc" size="14px" />
          </slot>
        </view>
      </view>

      <!-- 请选择 -->
      <view v-if="['custom', 'custom2'].includes(privateType)" class="nut-address__custom">
        <view class="nut-address__region">
          <view
            v-for="(item, index) in selectedRegion"
            :key="index"
            class="nut-address__region-item "
            :class="[index === tabIndex ? 'active' : '']"
            @click="changeRegionTab(item, index)"
          >
            <view>{{ getTabName(item, index) }} </view>
            <view class="nut-address__region-line--mini" :class="{ active: index === tabIndex }" />
          </view>
          <view v-if="tabIndex === selectedRegion.length" class="active nut-address__region-item">
            <view>{{ getTabName(null, selectedRegion.length) }} </view>
            <view class="nut-address__region-line--mini active" />
          </view>
        </view>

        <view v-if="privateType === 'custom'" class="nut-address__detail">
          <div class="nut-address__detail-list">
            <scroll-view
              :scroll-y="true"
              :style="{ height: '100%' }"
              :scroll-top="scrollTop"
              @scroll="scrollChange"
            >
              <div
                v-for="(item, index) in regionList"
                :key="index"
                class="nut-address__detail-item"
                :class="[selectedRegion[tabIndex]?.id === item.id ? 'active' : '']"
                @click="nextAreaList(item)"
              >
                <view>
                  <slot v-if="selectedRegion[tabIndex]?.id === item.id" name="icon">
                    <NutIcon name="Check" custom-class="nut-address-select-icon" width="13px" />
                  </slot>{{ item.name }}
                </view>
              </div>
            </scroll-view>
          </div>
        </view>

        <view v-else class="nut-address__elevator-group">
          <NutElevator
            :height="height"
            :index-list="transformData(regionList)"
            @click-item="handleElevatorItem"
          />
        </view>
      </view>

      <!-- 配送至 -->
      <view v-else-if="privateType === 'exist'" class="nut-address__exist">
        <div class="nut-address__exist-group">
          <ul class="nut-address__exist-group-list">
            <li
              v-for="(item, index) in existAddress"
              :key="index"
              class="nut-address__exist-group-item"
              :class="[item.selectedAddress ? 'active' : '']"
              @click="selectedExist(item)"
            >
              <slot v-if="!item.selectedAddress" name="unselectedIcon">
                <NutIcon name="location2" custom-class="nut-address-select-icon" width="13px" />
              </slot>

              <slot v-if="item.selectedAddress" name="icon">
                <NutIcon name="Check" custom-class="nut-address-select-icon" width="13px" />
              </slot>

              <div class="nut-address__exist-item-info">
                <div v-if="item.name && item.phone" class="nut-address__exist-item-info-top">
                  <div class="nut-address__exist-item-info-name">
                    {{ item.name }}
                  </div>
                  <div class="nut-address__exist-item-info-phone">
                    {{ item.phone }}
                  </div>
                </div>

                <div class="nut-address__exist-item-info-bottom">
                  <view>
                    {{ item.provinceName + item.cityName + item.countyName + item.townName + item.addressDetail }}
                  </view>
                </div>
              </div>
            </li>
          </ul>
        </div>
        <div v-if="isShowCustomAddress" class="nut-address__exist-choose" @click="switchModule">
          <div class="nut-address__exist-choose-btn">
            {{
              customAndExistTitle || translate('chooseAnotherAddress')
            }}
          </div>
        </div>
        <template v-if="!isShowCustomAddress">
          <slot name="bottom" />
        </template>
      </view>
    </view>
  </NutPopup>
</template>

<style lang="scss">
@import './index';
</style>
