<template>
  <section class="w-full space-y-6">
    <ElCard shadow="never" class="w-full">
      <template #header>
        <div class="flex flex-col gap-1">
          <div class="text-base font-semibold text-[var(--el-text-color-primary)]">
            {{ t('announcement.audience.title') }}
          </div>
          <div class="text-xs text-[var(--el-text-color-secondary)]">
            {{ t('announcement.audience.targetTypeHint') }}
          </div>
        </div>
      </template>

      <div class="space-y-3">
        <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
          {{ t('announcement.audience.targetType') }}
        </div>
        <ElRadioGroup v-model="localState.targetType" class="flex flex-wrap gap-4">
          <ElRadio v-for="item in targetTypeOptions" :key="item.value" :label="item.value">
            {{ t(item.labelKey) }}
          </ElRadio>
        </ElRadioGroup>
        <div class="text-xs text-[var(--el-text-color-secondary)]">
          {{ targetTypeHelper }}
        </div>
      </div>
    </ElCard>

    <ElCard v-if="isRoleMode" shadow="never" class="w-full">
      <template #header>
        <div class="text-sm font-semibold text-[var(--el-text-color-primary)]">
          {{ t('announcement.audience.type.roles') }}
        </div>
      </template>

      <div class="space-y-4">
        <div class="space-y-2">
          <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
            {{ t('announcement.audience.rules.roles') }}
          </div>

          <div v-loading="roleLoading" class="min-h-[48px]">
            <ElCheckboxGroup v-model="localState.rules.roles" class="flex flex-wrap gap-3">
              <ElCheckbox
                v-for="role in roleOptions"
                :key="role.id"
                :label="role.id"
                :disabled="role.disabled"
              >
                {{ role.label }}
              </ElCheckbox>
            </ElCheckboxGroup>
          </div>

          <ElEmpty
            v-if="!roleLoading && roleOptions.length === 0"
            :description="t('announcement.audience.rules.emptyRoles')"
            class="mt-2"
          />
        </div>

        <div
          class="flex flex-wrap items-center gap-2 text-xs text-[var(--el-text-color-secondary)]"
        >
          <span>{{ t('announcement.audience.rules.estimateLabel') }}</span>
          <ElTag type="info" effect="light">
            <span v-if="estimateLoading">{{
              t('announcement.audience.rules.estimateLoading')
            }}</span>
            <span v-else>{{ estimateState.count }}</span>
          </ElTag>
        </div>
      </div>
    </ElCard>

    <ElCard v-if="isRulesMode" shadow="never" class="w-full">
      <template #header>
        <div class="text-sm font-semibold text-[var(--el-text-color-primary)]">
          {{ t('announcement.audience.type.rules') }}
        </div>
      </template>

      <div class="space-y-4">
        <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
          <div class="space-y-2">
            <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
              {{ t('announcement.audience.rules.departments') }}
            </div>
            <ElTreeSelect
              v-model="localState.rules.departments"
              :data="departmentOptions"
              multiple
              show-checkbox
              node-key="value"
              class="w-full"
              :placeholder="t('announcement.audience.rules.departmentsPlaceholder')"
              :loading="departmentLoading"
              clearable
            />
            <ElEmpty
              v-if="!departmentLoading && departmentOptions.length === 0"
              :description="t('announcement.audience.rules.emptyDepartments')"
              class="mt-2"
            />
          </div>

          <div class="space-y-2">
            <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
              {{ t('announcement.audience.rules.roles') }}
            </div>
            <div v-loading="roleLoading" class="min-h-[48px]">
              <ElCheckboxGroup v-model="localState.rules.roles" class="flex flex-wrap gap-3">
                <ElCheckbox
                  v-for="role in roleOptions"
                  :key="role.id"
                  :label="role.id"
                  :disabled="role.disabled"
                >
                  {{ role.label }}
                </ElCheckbox>
              </ElCheckboxGroup>
            </div>
            <ElEmpty
              v-if="!roleLoading && roleOptions.length === 0"
              :description="t('announcement.audience.rules.emptyRoles')"
              class="mt-2"
            />
          </div>
        </div>

        <div class="space-y-2">
          <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
            {{ t('announcement.audience.rules.tags') }}
          </div>
          <ElSelect
            v-model="localState.rules.tags"
            multiple
            filterable
            allow-create
            default-first-option
            collapse-tags
            class="w-full"
            :placeholder="t('announcement.audience.rules.tagsPlaceholder')"
          >
            <ElOption
              v-for="tag in tagOptions"
              :key="tag.value"
              :label="tag.label"
              :value="tag.value"
            />
          </ElSelect>
        </div>

        <div
          class="flex flex-wrap items-center gap-2 text-xs text-[var(--el-text-color-secondary)]"
        >
          <span>{{ t('announcement.audience.rules.estimateLabel') }}</span>
          <ElTag type="info" effect="light">
            <span v-if="estimateLoading">{{
              t('announcement.audience.rules.estimateLoading')
            }}</span>
            <span v-else>{{ estimateState.count }}</span>
          </ElTag>
        </div>
      </div>
    </ElCard>

    <ElCard v-if="isUsersMode" shadow="never" class="w-full">
      <template #header>
        <div class="text-sm font-semibold text-[var(--el-text-color-primary)]">
          {{ t('announcement.audience.type.users') }}
        </div>
      </template>

      <div class="space-y-4">
        <ElSelect
          v-model="localState.userIds"
          multiple
          filterable
          remote
          clearable
          collapse-tags
          class="w-full"
          :remote-method="handleUserRemoteSearch"
          :loading="userLoading"
          :placeholder="t('announcement.audience.users.placeholder')"
        >
          <ElOption
            v-for="user in userOptions"
            :key="user.id"
            :label="user.label"
            :value="user.id"
          />
        </ElSelect>

        <div
          class="flex flex-wrap items-center gap-2 text-xs text-[var(--el-text-color-secondary)]"
        >
          <span>{{ t('announcement.audience.manual.estimateLabel') }}</span>
          <ElTag type="info" effect="light">{{ selectedUserCount }}</ElTag>
        </div>
      </div>
    </ElCard>

    <ElCard v-if="isManualMode" shadow="never" class="w-full">
      <template #header>
        <div class="text-sm font-semibold text-[var(--el-text-color-primary)]">
          {{ t('announcement.audience.type.manual') }}
        </div>
      </template>

      <div class="space-y-4">
        <ElAutocomplete
          v-model="manualQuery"
          class="w-full"
          :fetch-suggestions="handleUserSuggestions"
          :placeholder="t('announcement.audience.manual.searchPlaceholder')"
          :trigger-on-focus="false"
          :loading="userLoading"
          clearable
          @select="handleUserSelect"
        >
          <template #default="{ item }">
            <div class="flex flex-col">
              <span class="text-sm text-[var(--el-text-color-primary)]">
                {{ item.label }}
              </span>
              <span class="text-xs text-[var(--el-text-color-secondary)]">
                {{ item.option?.email || item.option?.phone || item.option?.id }}
              </span>
            </div>
          </template>
        </ElAutocomplete>

        <ElTransfer
          v-model="localState.userIds"
          :data="manualTransferData"
          :titles="manualTransferTitles"
          filterable
          :filter-placeholder="t('announcement.audience.manual.filterPlaceholder')"
          class="w-full"
        >
          <template #default="{ option }">
            <span class="text-sm">{{ option.label }}</span>
          </template>
        </ElTransfer>

        <div
          class="flex flex-wrap items-center gap-2 text-xs text-[var(--el-text-color-secondary)]"
        >
          <span>{{ t('announcement.audience.manual.estimateLabel') }}</span>
          <ElTag type="info" effect="light">{{ selectedUserCount }}</ElTag>
        </div>
      </div>
    </ElCard>
  </section>
</template>

<script setup lang="ts">
  import { useDebounceFn } from '@vueuse/core'
  import { useI18n } from 'vue-i18n'
  import { fetchGetTenantRoles } from '@/api/tenant-role'
  import { fetchGetUserList } from '@/api/system-manage'
  import { useAnnouncementStore } from '@/store/modules/announcement'
  import { useUserStore } from '@/store/modules/user'
  import type { AnnouncementTargetType, AudienceEstimate, TargetRules } from '@/types/announcement'

  defineOptions({ name: 'AudienceSelector' })

  interface Props {
    modelValue: {
      targetType: AnnouncementTargetType
      targetRules?: TargetRules
      targetUserIds?: string[]
    }
  }

  interface Emits {
    (e: 'update:modelValue', value: Props['modelValue']): void
    (e: 'estimate-change', value: AudienceEstimate): void
  }

  const { modelValue } = defineProps<Props>()
  const emit = defineEmits<Emits>()

  const { t } = useI18n()
  const announcementStore = useAnnouncementStore()
  const userStore = useUserStore()

  // 1. 选项数据结构定义
  interface DepartmentOption {
    value: string
    label: string
    children?: DepartmentOption[]
  }

  interface RoleOption {
    id: string
    label: string
    code: string
    disabled: boolean
  }

  interface TagOption {
    value: string
    label: string
  }

  interface UserOption {
    id: string
    label: string
    name?: string
    phone?: string
    email?: string
  }

  interface UserSuggestion {
    value: string
    label: string
    id: string
    option: UserOption
  }

  interface TransferItem {
    key: string
    label: string
    disabled?: boolean
  }

  const targetTypeOptions: Array<{ value: AnnouncementTargetType; labelKey: string }> = [
    { value: 'All', labelKey: 'announcement.audience.type.all' },
    { value: 'Roles', labelKey: 'announcement.audience.type.roles' },
    { value: 'Users', labelKey: 'announcement.audience.type.users' },
    { value: 'Rules', labelKey: 'announcement.audience.type.rules' },
    { value: 'Manual', labelKey: 'announcement.audience.type.manual' }
  ]

  const targetTypeHelperMap: Record<AnnouncementTargetType, string> = {
    All: 'announcement.audience.helper.all',
    Roles: 'announcement.audience.helper.roles',
    Users: 'announcement.audience.helper.users',
    Rules: 'announcement.audience.helper.rules',
    Manual: 'announcement.audience.helper.manual'
  }

  // 2. 本地状态与加载状态
  const currentTenantId = computed(() => String(userStore.info?.tenantId || ''))
  const localState = reactive({
    targetType: 'All' as AnnouncementTargetType,
    rules: {
      departments: [] as string[],
      roles: [] as string[],
      tags: [] as string[]
    },
    userIds: [] as string[]
  })

  const roleOptions = ref<RoleOption[]>([])
  const departmentOptions = ref<DepartmentOption[]>([])
  const tagOptions = ref<TagOption[]>([])
  const userOptions = ref<UserOption[]>([])

  const roleLoading = ref(false)
  const departmentLoading = ref(false)
  const userLoading = ref(false)
  const estimateLoading = ref(false)

  const estimateState = ref<AudienceEstimate>({ count: 0, preview: [] })
  const manualQuery = ref('')
  const isSyncing = ref(false)

  // 3. 计算属性
  const isRoleMode = computed(() => localState.targetType === 'Roles')
  const isUsersMode = computed(() => localState.targetType === 'Users')
  const isRulesMode = computed(() => localState.targetType === 'Rules')
  const isManualMode = computed(() => localState.targetType === 'Manual')
  const isRulesOrRoles = computed(() => isRulesMode.value || isRoleMode.value)

  const selectedUserCount = computed(() => localState.userIds.length)

  const targetTypeHelper = computed(() => {
    return t(targetTypeHelperMap[localState.targetType])
  })

  const manualTransferData = computed<TransferItem[]>(() => {
    return userOptions.value.map((user) => ({
      key: user.id,
      label: user.label
    }))
  })

  const manualTransferTitles = computed<[string, string]>(() => [
    t('announcement.audience.manual.transferLeft'),
    t('announcement.audience.manual.transferRight')
  ])

  // 4. 数据清洗与模型构建
  const normalizeArray = (value?: string[]) => {
    // 1. 空值回退
    const list = Array.isArray(value) ? value : []

    // 2. 去重并过滤空白
    return Array.from(
      new Set(list.map((item) => String(item)).filter((item) => item.trim().length > 0))
    )
  }

  const normalizeRules = (rules?: TargetRules) => {
    // 1. 统一格式化三类规则
    return {
      departments: normalizeArray(rules?.departments),
      roles: normalizeArray(rules?.roles),
      tags: normalizeArray(rules?.tags)
    }
  }

  const buildRulesPayload = (
    mode: Extract<AnnouncementTargetType, 'Rules' | 'Roles'>
  ): TargetRules => {
    // 1. 获取清洗后的规则数据
    const cleaned = normalizeRules(localState.rules)

    // 2. 角色模式仅返回角色规则
    if (mode === 'Roles') {
      return {
        roles: cleaned.roles
      }
    }

    // 3. 规则模式返回全部规则
    return cleaned
  }

  const buildModelValue = (): Props['modelValue'] => {
    // 1. 初始化基础结构
    const targetType = localState.targetType

    // 2. 角色与规则模式
    if (targetType === 'Roles' || targetType === 'Rules') {
      const rules = buildRulesPayload(targetType)
      const hasRules =
        (rules.departments && rules.departments.length > 0) ||
        (rules.roles && rules.roles.length > 0) ||
        (rules.tags && rules.tags.length > 0)

      return {
        targetType,
        ...(hasRules ? { targetRules: rules } : {})
      }
    }

    // 3. 指定用户与手动选择
    if (targetType === 'Users' || targetType === 'Manual') {
      const userIds = normalizeArray(localState.userIds)

      return {
        targetType,
        ...(userIds.length > 0 ? { targetUserIds: userIds } : {})
      }
    }

    // 4. 全部用户
    return { targetType }
  }

  const emitModelValue = () => {
    // 1. 避免同步阶段触发外部更新
    if (isSyncing.value) return

    // 2. 对外发送最新模型
    emit('update:modelValue', buildModelValue())
  }

  // 5. 受众预估处理
  const emitEstimate = (estimate: AudienceEstimate) => {
    // 1. 更新本地缓存
    estimateState.value = estimate

    // 2. 同步到外部监听
    emit('estimate-change', estimate)
  }

  const updateUserEstimate = () => {
    // 1. 构建用户预览
    const userIds = normalizeArray(localState.userIds)

    // 2. 发送预估结果
    emitEstimate({
      count: userIds.length,
      preview: userIds.slice(0, 10)
    })
  }

  const triggerRuleEstimate = useDebounceFn(async () => {
    // 1. 仅规则/角色模式触发
    if (!isRulesOrRoles.value) return

    const targetType = localState.targetType
    if (targetType !== 'Rules' && targetType !== 'Roles') return

    // 2. 发起预估请求
    estimateLoading.value = true
    const rules = buildRulesPayload(targetType)
    const estimate = await announcementStore.estimateAudience(rules)

    // 3. 更新预估结果
    estimateLoading.value = false
    emitEstimate(estimate)
  }, 400)

  const refreshEstimateByType = () => {
    // 1. 规则/角色模式走实时预估
    if (isRulesOrRoles.value) {
      triggerRuleEstimate()
      return
    }

    // 2. 用户模式直接统计
    if (isUsersMode.value || isManualMode.value) {
      updateUserEstimate()
    }
  }

  // 6. 角色数据加载
  const loadRoles = async () => {
    // 1. 标记加载状态
    roleLoading.value = true

    try {
      // 2. 拉取角色列表
      const tenantId = currentTenantId.value
      if (!tenantId) {
        roleOptions.value = []
        return
      }

      // 3. 执行查询
      const result = await fetchGetTenantRoles(tenantId, { Page: 1, PageSize: 200 })
      const records = Array.isArray(result?.items) ? result.items : []

      // 4. 映射为选择项
      roleOptions.value = records.map((role) => ({
        id: String(role.id),
        label: role.name || role.code,
        code: role.code,
        disabled: false
      }))
    } catch {
      // 1. 失败提示
      ElMessage.error(t('announcement.audience.errors.loadRolesFailed'))
      roleOptions.value = []
    } finally {
      // 2. 关闭加载状态
      roleLoading.value = false
    }
  }

  // 7. 用户搜索与候选缓存
  type UserListItem = Api.SystemManage.UserListItem
  type UserSearchParams = Api.SystemManage.UserSearchParams

  const resolveUserLabel = (user: UserListItem) => {
    // 1. 优先展示昵称或账号
    if (user.displayName) return user.displayName
    if (user.account) return user.account

    // 2. 回退手机号/邮箱
    if (user.phone) return user.phone
    if (user.email) return user.email

    // 3. 最后回退ID
    return String(user.userId)
  }

  const buildUserOption = (user: UserListItem): UserOption => {
    // 1. 生成基础字段
    return {
      id: String(user.userId),
      label: resolveUserLabel(user),
      name: user.displayName,
      phone: user.phone,
      email: user.email
    }
  }

  const upsertUserOption = (option: UserOption) => {
    // 1. 查找已有项
    const index = userOptions.value.findIndex((item) => item.id === option.id)

    // 2. 覆盖或追加
    if (index >= 0) {
      userOptions.value.splice(index, 1, option)
    } else {
      userOptions.value.push(option)
    }
  }

  const ensureUserOptions = (ids: string[]) => {
    // 1. 生成已有ID集合
    const existingIds = new Set(userOptions.value.map((item) => item.id))

    // 2. 补齐未知用户占位
    ids.forEach((id) => {
      if (!existingIds.has(id)) {
        userOptions.value.push({
          id,
          label: t('announcement.audience.users.unknownUser', { id })
        })
      }
    })
  }

  const buildUserSearchParams = (keyword: string): UserSearchParams => {
    // 1. 默认分页参数
    const params: UserSearchParams = { Page: 1, PageSize: 20 }

    // 2. 使用统一关键词检索
    return {
      ...params,
      Keyword: keyword
    }
  }

  const searchUsers = async (keyword: string) => {
    // 1. 清洗关键词
    const query = keyword.trim()
    if (!query) return [] as UserOption[]

    userLoading.value = true

    try {
      // 2. 发起搜索请求
      const params = buildUserSearchParams(query)
      const result = await fetchGetUserList(params)
      const records = Array.isArray(result?.items) ? result.items : []

      // 3. 转为候选选项
      const options = records.map((user) => buildUserOption(user))
      options.forEach((option) => upsertUserOption(option))

      return options
    } catch {
      // 1. 失败提示
      ElMessage.error(t('announcement.audience.errors.loadUsersFailed'))
      return [] as UserOption[]
    } finally {
      // 2. 关闭加载状态
      userLoading.value = false
    }
  }

  const fetchUserSuggestionsDebounced = useDebounceFn(async (queryString: string) => {
    // 1. 拉取候选用户
    const options = await searchUsers(queryString)

    // 2. 转换为自动完成格式
    return options.map(
      (option): UserSuggestion => ({
        value: option.label,
        label: option.label,
        id: option.id,
        option
      })
    )
  }, 300)

  const handleUserSuggestions = (
    queryString: string,
    callback: (results: UserSuggestion[]) => void
  ) => {
    void fetchUserSuggestionsDebounced(queryString)
      .then((suggestions) => callback(suggestions))
      .catch(() => callback([]))
  }

  const handleUserSelect = (item: Record<string, any>) => {
    const suggestion = item as UserSuggestion
    // 1. 写入候选列表
    upsertUserOption(suggestion.option)

    // 2. 追加到已选列表
    if (!localState.userIds.includes(suggestion.id)) {
      localState.userIds = [...localState.userIds, suggestion.id]
    }

    // 3. 清空搜索框
    manualQuery.value = ''
  }

  const handleUserRemoteSearch = (query: string) => {
    // 1. 指定用户模式触发搜索
    if (!query.trim()) return

    searchUsers(query)
  }

  // 8. Props 同步处理
  const syncFromProps = (value: Props['modelValue']) => {
    // 1. 标记同步中
    isSyncing.value = true

    // 2. 同步目标类型
    localState.targetType = value?.targetType ?? 'All'

    // 3. 同步规则与用户列表
    const normalizedRules = normalizeRules(value?.targetRules)
    localState.rules.departments = normalizedRules.departments
    localState.rules.roles = normalizedRules.roles
    localState.rules.tags = normalizedRules.tags
    localState.userIds = normalizeArray(value?.targetUserIds)

    // 4. 补齐未知用户占位
    ensureUserOptions(localState.userIds)

    nextTick(() => {
      // 1. 完成同步并刷新预估
      isSyncing.value = false
      refreshEstimateByType()
    })
  }

  watch(
    () => modelValue,
    (value) => syncFromProps(value),
    { deep: true, immediate: true }
  )

  // 9. 监听本地变更并向外同步
  watch(
    () => localState.targetType,
    () => {
      if (isSyncing.value) return
      emitModelValue()
      refreshEstimateByType()
    }
  )

  watch(
    () => localState.rules,
    () => {
      if (isSyncing.value) return
      emitModelValue()

      if (isRulesOrRoles.value) {
        triggerRuleEstimate()
      }
    },
    { deep: true }
  )

  watch(
    () => localState.userIds,
    () => {
      if (isSyncing.value) return
      emitModelValue()

      if (isUsersMode.value || isManualMode.value) {
        updateUserEstimate()
      }
    },
    { deep: true }
  )

  // 10. 初始化动作
  onMounted(() => {
    loadRoles()
  })

  // 11. 监听租户变化
  watch(
    () => currentTenantId.value,
    (value) => {
      if (!value) return
      loadRoles()
    }
  )
</script>
