<template>
  <Dialog :title="dialogTitle" v-model="dialogVisible">
    <el-form
      ref="formRef"
      :model="formData"
      :rules="formRules"
      label-width="100px"
      v-loading="formLoading"
    >
      <el-divider content-position="left">基本信息</el-divider>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="客户名称" prop="customerName">
            <el-input v-model="formData.customerName" placeholder="请输入客户名称" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="客户编码" prop="customerCode">
            <el-input v-model="formData.customerCode" placeholder="请输入客户编码" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="售后负责人" prop="afterSalesManager">
            <el-input v-model="formData.afterSalesManager" placeholder="请输入售后负责人" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="状态" prop="status">
            <el-radio-group v-model="formData.status">
              <el-radio
                v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
                :key="dict.value"
                :value="dict.value"
              >
                {{ dict.label }}
              </el-radio>
            </el-radio-group>
          </el-form-item>
        </el-col>
      </el-row>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
      </el-form-item>

      <el-divider content-position="left">区域信息</el-divider>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="国家" prop="countryCode">
            <country-select
              v-model="formData.countryCode"
              :country="formData.countryCode"
              top-country="CN"
              placeholder="请选择国家"
              class-name="w-full el-country-select"
              :search-able="true"
              :disable-placeholder="true"
            />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item
            :label="isChina ? '省市' : '省/州'"
            :prop="isChina ? 'areaIds' : 'provinceName'"
          >
            <el-cascader
              v-if="isChina"
              v-model="formData.areaIds"
              class="w-full"
              :options="areaTree"
              :props="areaCascaderProps"
              clearable
              filterable
              placeholder="请选择省/市"
              @change="handleAreaChange"
            />
            <region-select
              v-else
              v-model="formData.provinceName"
              :region="formData.provinceName"
              :country="formData.countryCode"
              placeholder="请选择省/州"
              class-name="w-full el-country-select"
              :search-able="true"
              :disable-placeholder="true"
              :region-name="true"
            />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="!isChina" :gutter="20">
        <el-col :span="12">
          <el-form-item label="城市" prop="cityName">
            <el-input v-model="formData.cityName" placeholder="请输入城市" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="详细地址" prop="address">
            <el-input v-model="formData.address" placeholder="请输入详细地址" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="经度" prop="longitude">
            <el-input v-model="formData.longitude" placeholder="请输入经度" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="纬度" prop="latitude">
            <el-input v-model="formData.latitude" placeholder="请输入纬度" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script setup lang="ts">
import { ManagementApi, Management } from '@/api/cus/management'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import { getAreaTree } from '@/api/system/area'

/** 客户管理 表单 */
defineOptions({ name: 'ManagementForm' })

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
type FormModel = Partial<Management> & {
  areaIds?: number[]
}

const formData = ref<FormModel>({
  id: undefined,
  customerCode: undefined,
  customerName: undefined,
  status: CommonStatusEnum.ENABLE,
  remark: undefined,
  afterSalesManager: undefined,
  countryCode: 'CN',
  countryName: '中国',
  areaIds: undefined,
  provinceCode: undefined,
  provinceName: undefined,
  cityCode: undefined,
  cityName: undefined,
  address: undefined,
  longitude: undefined,
  latitude: undefined,
  dbIp: undefined,
  dbPort: undefined,
  dbUsername: undefined,
  dbPassword: undefined
})
const formRules = reactive({
  customerName: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
  customerCode: [{ required: true, message: '客户编码不能为空', trigger: 'blur' }],
  status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref

const isChina = computed(() => formData.value.countryCode === 'CN')

const countryMetaLoaded = ref(false)
const countryCodeToName = ref(new Map<string, string>([['CN', '中国']]))
const countryNameToCode = ref(new Map<string, string>([['中国', 'CN']]))
const syncingForm = ref(false)

type AreaVO = {
  id: number
  name: string
  code: string
  parentId?: number
  children?: AreaVO[]
}

const areaTree = ref<AreaVO[]>([])
const areaCascaderProps = {
  label: 'name',
  value: 'id',
  children: 'children',
  emitPath: true,
  checkStrictly: true
}
const areaIdToNode = ref(new Map<number, AreaVO>())
const areaIdToParentId = ref(new Map<number, number | undefined>())
const areaCodeToId = ref(new Map<string, number>())

const rebuildAreaIndex = (tree: AreaVO[]) => {
  const idToNode = new Map<number, AreaVO>()
  const idToParent = new Map<number, number | undefined>()
  const codeToId = new Map<string, number>()
  const walk = (nodes: AreaVO[], parentId?: number) => {
    nodes.forEach((n) => {
      idToNode.set(n.id, n)
      idToParent.set(n.id, parentId)
      if (n.code) {
        codeToId.set(n.code, n.id)
      }
      if (n.children?.length) walk(n.children, n.id)
    })
  }
  walk(tree)
  areaIdToNode.value = idToNode
  areaIdToParentId.value = idToParent
  areaCodeToId.value = codeToId
}

const buildPathById = (id: number) => {
  const path: number[] = []
  let current: number | undefined = id
  while (current !== undefined) {
    path.push(current)
    current = areaIdToParentId.value.get(current)
  }
  return path.reverse()
}

const syncAreaIdsFromCodes = () => {
  const cityId = formData.value.cityCode
    ? areaCodeToId.value.get(formData.value.cityCode)
    : undefined
  const provinceId = formData.value.provinceCode
    ? areaCodeToId.value.get(formData.value.provinceCode)
    : undefined
  const targetId = cityId ?? provinceId
  if (!targetId) return
  formData.value.areaIds = buildPathById(targetId)
}

const handleAreaChange = (value?: number[]) => {
  if (!value?.length) {
    formData.value.provinceCode = undefined
    formData.value.provinceName = undefined
    formData.value.cityCode = undefined
    formData.value.cityName = undefined
    return
  }
  const ids = value
  const provinceNode = ids[0] ? areaIdToNode.value.get(ids[0]) : undefined
  const cityNode = ids[1] ? areaIdToNode.value.get(ids[1]) : undefined

  formData.value.provinceCode = provinceNode?.code
  formData.value.provinceName = provinceNode?.name
  formData.value.cityCode = cityNode?.code
  formData.value.cityName = cityNode?.name
}

const handleCountryChange = async (countryCode?: string) => {
  const code = countryCode || undefined
  formData.value.countryName = code ? countryCodeToName.value.get(code) || code : undefined
  formData.value.areaIds = undefined
  handleAreaChange(undefined)
  if (code) await ensureAreaTreeLoaded(code)
}

watch(
  () => formData.value.countryCode,
  (code) => {
    if (!dialogVisible.value) return
    if (syncingForm.value) return
    void handleCountryChange(code)
  }
)

const loadedCountryCode = ref<string | undefined>(undefined)
const ensureAreaTreeLoaded = async (countryCode?: string) => {
  if (countryCode && countryCode !== 'CN') {
    areaTree.value = []
    rebuildAreaIndex([])
    loadedCountryCode.value = countryCode
    return
  }
  if (loadedCountryCode.value === countryCode && areaTree.value.length) return
  const tree = (await getAreaTree(countryCode)) || []
  areaTree.value = tree
  rebuildAreaIndex(tree)
  loadedCountryCode.value = countryCode
}

/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  dialogVisible.value = true
  dialogTitle.value = t('action.' + type)
  formType.value = type
  syncingForm.value = true
  resetForm()
  if (!formData.value.countryCode && formData.value.countryName) {
    formData.value.countryCode = countryNameToCode.value.get(formData.value.countryName)
  }
  await ensureAreaTreeLoaded(formData.value.countryCode)
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      formData.value = await ManagementApi.getManagement(id)
      if (!formData.value.countryCode && formData.value.countryName) {
        formData.value.countryCode = countryNameToCode.value.get(formData.value.countryName)
      }
      formData.value.countryName = formData.value.countryCode
        ? countryCodeToName.value.get(formData.value.countryCode) || formData.value.countryName
        : formData.value.countryName
      await ensureAreaTreeLoaded(formData.value.countryCode)
      syncAreaIdsFromCodes()
      handleAreaChange(formData.value.areaIds as any)
    } finally {
      formLoading.value = false
    }
  }
  syncingForm.value = false
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  await formRef.value.validate()
  // 提交请求
  formLoading.value = true
  try {
    const data = formData.value as unknown as Management
    if (formType.value === 'create') {
      await ManagementApi.createManagement(data)
      message.success(t('common.createSuccess'))
    } else {
      await ManagementApi.updateManagement(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
    customerCode: undefined,
    customerName: undefined,
    status: CommonStatusEnum.ENABLE,
    remark: undefined,
    afterSalesManager: undefined,
    countryCode: 'CN',
    countryName: '中国',
    areaIds: undefined,
    provinceCode: undefined,
    provinceName: undefined,
    cityCode: undefined,
    cityName: undefined,
    address: undefined,
    longitude: undefined,
    latitude: undefined,
    dbIp: undefined,
    dbPort: undefined,
    dbUsername: undefined,
    dbPassword: undefined
  }
  formRef.value?.resetFields()
}
</script>

<style scoped lang="scss">
:deep(select.el-country-select) {
  width: 100%;
  height: var(--el-component-size, 32px);
  padding: 0 30px 0 11px;
  border: 1px solid var(--el-border-color);
  border-radius: var(--el-border-radius-base);
  background-color: var(--el-input-bg-color, var(--el-bg-color));
  color: var(--el-text-color-regular);
  font-size: var(--el-font-size-base);
  outline: none;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease,
    background-color 0.2s ease;
}

:deep(select.el-country-select:focus) {
  border-color: var(--el-color-primary);
  box-shadow: 0 0 0 1px var(--el-color-primary) inset;
}

:deep(select.el-country-select:disabled) {
  background-color: var(--el-disabled-bg-color);
  color: var(--el-disabled-text-color);
  cursor: not-allowed;
}
</style>
