<template>
  <div class="user-page art-full-height">
    <UserSearch
      v-model="searchForm"
      :role-options="searchRoleOptions"
      :tenant-options="tenantOptions"
      :is-super-admin="isSuperAdmin"
      @search="handleSearch"
      @reset="handleReset"
    />

    <ElCard class="art-table-card" shadow="never">
      <ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
        <template #left>
          <ElSpace wrap>
            <ElButton type="primary" @click="openCreateDialog" v-ripple>
              <template #icon><ArtSvgIcon icon="ri:add-line" /></template>
              {{ t('user.action.create') }}
            </ElButton>
            <ElDropdown @command="handleBatchCommand">
              <ElButton>
                {{ t('user.batch.title') }}
                <ElIcon class="ml-1"><ArrowDown /></ElIcon>
              </ElButton>
              <template #dropdown>
                <ElDropdownMenu>
                  <ElDropdownItem
                    v-for="action in batchActions"
                    :key="action.value"
                    :command="action.value"
                  >
                    {{ action.label }}
                  </ElDropdownItem>
                </ElDropdownMenu>
              </template>
            </ElDropdown>
          </ElSpace>
        </template>
        <template #right>
          <span class="text-xs text-[var(--el-text-color-secondary)]">
            {{ t('user.batch.selected', { count: selectedCount }) }}
          </span>
        </template>
      </ArtTableHeader>

      <ArtTable
        ref="tableRef"
        :loading="loading"
        :data="data"
        :columns="columns"
        :pagination="pagination"
        row-key="userId"
        :reserve-selection="true"
        @selection-change="handleSelectionChange"
        @pagination:size-change="handleSizeChange"
        @pagination:current-change="handleCurrentChange"
      >
        <template #tenant="{ row }">
          <span>{{ resolveTenantLabel(row.tenantId) }}</span>
        </template>
        <template #avatar="{ row }">
          <ElAvatar :src="row.avatar" :size="32">
            {{ resolveAvatarText(row) }}
          </ElAvatar>
        </template>
        <template #roles="{ row }">
          <div class="flex flex-wrap gap-1">
            <ElTag v-for="role in row.roles" :key="role" type="info" effect="light">
              {{ resolveRoleLabel(role) }}
            </ElTag>
            <span
              v-if="row.roles.length === 0"
              class="text-xs text-[var(--el-text-color-secondary)]"
            >
              {{ t('user.empty.roles') }}
            </span>
          </div>
        </template>
        <template #status="{ row }">
          <ElTag :type="resolveStatusInfo(row).type">
            {{ resolveStatusInfo(row).label }}
          </ElTag>
        </template>
        <template #actions="{ row }">
          <div class="action-wrap">
            <button class="art-action-btn" type="button" @click="openDetail(row)">
              <ArtSvgIcon icon="ri:information-line" class="art-action-icon" />
              <span>{{ t('dictionary.common.detail') }}</span>
            </button>
            <button
              v-if="!row.isDeleted"
              class="art-action-btn primary"
              type="button"
              @click="openEditDialog(row)"
            >
              <ArtSvgIcon icon="ri:edit-2-line" class="art-action-icon" />
              <span>{{ t('user.action.edit') }}</span>
            </button>
            <ElDropdown @command="(cmd) => handleRowCommand(row, cmd as RowAction)">
              <button class="art-action-btn info" type="button">
                <ArtSvgIcon icon="ri:more-2-line" class="art-action-icon" />
                <span>{{ t('user.action.more') }}</span>
              </button>
              <template #dropdown>
                <ElDropdownMenu>
                  <ElDropdownItem
                    v-if="!row.isDeleted && row.isLocked"
                    command="unlock"
                    :disabled="isRowActionDisabled(row, 'unlock')"
                  >
                    <span class="dropdown-item">
                      <ArtSvgIcon icon="ri:lock-unlock-line" class="dropdown-icon" />
                      <span>{{ t('user.action.unlock') }}</span>
                    </span>
                  </ElDropdownItem>
                  <ElDropdownItem
                    v-else-if="!row.isDeleted && row.status === 1"
                    command="disable"
                    :disabled="isRowActionDisabled(row, 'disable')"
                  >
                    <span class="dropdown-item">
                      <ArtSvgIcon icon="ri:close-circle-line" class="dropdown-icon" />
                      <span>{{ t('user.action.disable') }}</span>
                    </span>
                  </ElDropdownItem>
                  <ElDropdownItem
                    v-else-if="!row.isDeleted"
                    command="enable"
                    :disabled="isRowActionDisabled(row, 'enable')"
                  >
                    <span class="dropdown-item">
                      <ArtSvgIcon icon="ri:check-circle-line" class="dropdown-icon" />
                      <span>{{ t('user.action.enable') }}</span>
                    </span>
                  </ElDropdownItem>
                  <ElDropdownItem v-if="!row.isDeleted" command="reset">
                    <span class="dropdown-item">
                      <ArtSvgIcon icon="ri:refresh-line" class="dropdown-icon" />
                      <span>{{ t('user.action.resetPassword') }}</span>
                    </span>
                  </ElDropdownItem>
                  <ElDropdownItem
                    v-if="row.isDeleted"
                    command="restore"
                    :disabled="isRowActionDisabled(row, 'restore')"
                  >
                    <span class="dropdown-item">
                      <ArtSvgIcon icon="ri:arrow-go-back-line" class="dropdown-icon" />
                      <span>{{ t('user.action.restore') }}</span>
                    </span>
                  </ElDropdownItem>
                  <ElDropdownItem
                    v-else
                    divided
                    command="delete"
                    :disabled="isRowActionDisabled(row, 'delete')"
                  >
                    <span class="dropdown-item danger">
                      <ArtSvgIcon icon="ri:delete-bin-line" class="dropdown-icon" />
                      <span>{{ t('user.action.delete') }}</span>
                    </span>
                  </ElDropdownItem>
                </ElDropdownMenu>
              </template>
            </ElDropdown>
          </div>
        </template>
      </ArtTable>
    </ElCard>

    <UserDialog
      v-model:visible="dialogVisible"
      :type="dialogType"
      :user-data="dialogUserData"
      :role-options="dialogRoleOptions"
      :tenant-options="tenantOptions"
      :status-options="dialogStatusOptions"
      :is-super-admin="isSuperAdmin"
      :default-tenant-id="dialogDefaultTenantId"
      :loading="dialogLoading"
      @submit="handleDialogSubmit"
      @tenant-change="handleDialogTenantChange"
    />

    <ElDrawer
      v-model="detailVisible"
      :title="t('user.detail.title')"
      size="33.333%"
      :with-header="true"
    >
      <div v-loading="detailLoading" class="space-y-4">
        <ElDescriptions :column="1" border>
          <ElDescriptionsItem :label="t('user.field.userId')">
            {{ detailData?.userId || '-' }}
          </ElDescriptionsItem>
          <ElDescriptionsItem v-if="isSuperAdmin" :label="t('user.field.tenant')">
            {{ resolveTenantLabel(detailData?.tenantId || '') }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.account')">
            {{ detailData?.account || '-' }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.displayName')">
            {{ detailData?.displayName || '-' }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.phone')">
            {{ detailData?.phone || '-' }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.email')">
            {{ detailData?.email || '-' }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.status')">
            <ElTag :type="resolveDetailStatus.type">
              {{ resolveDetailStatus.label }}
            </ElTag>
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.createdAt')">
            {{ formatDateTime(detailData?.createdAt) }}
          </ElDescriptionsItem>
          <ElDescriptionsItem :label="t('user.field.lastLoginAt')">
            {{ formatDateTime(detailData?.lastLoginAt) }}
          </ElDescriptionsItem>
        </ElDescriptions>

        <div class="space-y-2">
          <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
            {{ t('user.detail.rolesTitle') }}
          </div>
          <div class="flex flex-wrap gap-1">
            <ElTag v-for="role in detailData?.roles || []" :key="role" type="info" effect="light">
              {{ resolveRoleLabel(role) }}
            </ElTag>
            <span
              v-if="!detailData || detailData.roles.length === 0"
              class="text-xs text-[var(--el-text-color-secondary)]"
            >
              {{ t('user.empty.roles') }}
            </span>
          </div>
        </div>

        <div class="space-y-2">
          <div class="text-sm font-medium text-[var(--el-text-color-primary)]">
            {{ t('user.detail.permissionsTitle') }}
          </div>
          <div class="flex flex-wrap gap-1">
            <ElTag
              v-for="permission in detailData?.permissions || []"
              :key="permission"
              type="success"
              effect="light"
            >
              {{ resolvePermissionLabel(permission) }}
            </ElTag>
            <span
              v-if="!detailData || detailData.permissions.length === 0"
              class="text-xs text-[var(--el-text-color-secondary)]"
            >
              {{ t('user.empty.permissions') }}
            </span>
          </div>
        </div>
      </div>
    </ElDrawer>
  </div>
</template>

<script setup lang="ts">
  import FileSaver from 'file-saver'
  import { useI18n } from 'vue-i18n'
  import { ArrowDown } from '@element-plus/icons-vue'
  import { ElMessage, ElMessageBox } from 'element-plus'
  import { useTable } from '@/hooks/core/useTable'
  import { useUserStore } from '@/store/modules/user'
  import type { ColumnOption } from '@/types/component'
  import { formatDateTime } from '@/utils/billing'
  import { isHttpError } from '@/utils/http/error'
  import {
    fetchGetUserList,
    fetchGetUserDetail,
    fetchCreateUser,
    fetchUpdateUser,
    fetchDeleteUser,
    fetchRestoreUser,
    fetchChangeUserStatus,
    fetchResetUserPassword,
    fetchBatchUserOperation
  } from '@/api/system-manage'
  import { fetchGetPermissionTree } from '@/api/permission'
  import { fetchGetTenantRoles } from '@/api/tenant-role'
  import { fetchGetTenantList } from '@/api/tenant'
  import ArtTable from '@/components/core/tables/art-table/index.vue'
  import ArtTableHeader from '@/components/core/tables/art-table-header/index.vue'
  import ArtSvgIcon from '@/components/core/base/art-svg-icon/index.vue'
  import UserSearch from './modules/user-search.vue'
  import UserDialog from './modules/user-dialog.vue'

  defineOptions({ name: 'User' })

  // 1. 类型与常量
  type UserListItem = Api.SystemManage.UserListItem
  type UserDetailDto = Api.SystemManage.UserDetailDto
  type IdentityUserStatus = Api.SystemManage.IdentityUserStatus
  type PermissionDto = Api.Permission.PermissionDto

  type DialogType = 'add' | 'edit'
  type RowAction = 'enable' | 'disable' | 'unlock' | 'reset' | 'delete' | 'restore'
  type BatchAction = 'enable' | 'disable' | 'delete' | 'restore' | 'export'

  interface SelectOption {
    label: string
    value: string | number
    disabled?: boolean
  }

  interface UserSearchForm {
    keyword?: string
    status?: IdentityUserStatus
    roleId?: string
    createdRange?: [string, string] | []
    lastLoginRange?: [string, string] | []
    includeDeleted?: boolean
    tenantId?: string
  }

  type UserDialogSubmitPayload =
    | { type: 'add'; data: Api.SystemManage.CreateIdentityUserCommand }
    | { type: 'edit'; data: Api.SystemManage.UpdateIdentityUserCommand }

  const superAdminRoleCodes = new Set([
    'super-admin',
    'super_admin',
    'platformadmin',
    'platform-admin'
  ])

  // 2. 依赖与基础状态
  const { t } = useI18n()
  const userStore = useUserStore()

  const isSuperAdmin = computed(() => {
    const roles = userStore.info?.roles ?? []
    return roles.some((role) => superAdminRoleCodes.has(role.trim().toLowerCase()))
  })

  const searchForm = ref<UserSearchForm>({
    keyword: '',
    status: undefined,
    roleId: undefined,
    createdRange: [],
    lastLoginRange: [],
    includeDeleted: false,
    tenantId: undefined
  })

  const tenantOptions = ref<SelectOption[]>([])
  const searchRoleOptions = ref<SelectOption[]>([])
  const dialogRoleOptions = ref<SelectOption[]>([])
  const roleLabelMap = ref<Map<string, string>>(new Map())
  const permissionLabelMap = ref<Map<string, string>>(new Map())

  const currentTenantId = computed(() => String(userStore.info?.tenantId || ''))

  // 3. 选项与状态映射
  const dialogStatusOptions = computed<SelectOption[]>(() => [
    { label: t('user.status.active'), value: 1 },
    { label: t('user.status.disabled'), value: 2 },
    { label: t('user.status.locked'), value: 3 }
  ])

  const batchActions = computed(() => [
    { value: 'enable', label: t('user.batch.enable') },
    { value: 'disable', label: t('user.batch.disable') },
    { value: 'delete', label: t('user.batch.delete') },
    { value: 'restore', label: t('user.batch.restore') },
    { value: 'export', label: t('user.batch.export') }
  ])

  const resolveStatusInfo = (row: {
    status: IdentityUserStatus
    isLocked: boolean
    isDeleted?: boolean
  }) => {
    // 1. 已删除状态
    if (row.isDeleted) {
      return { label: t('user.status.deleted'), type: 'info' as const }
    }

    // 2. 锁定状态优先
    if (row.isLocked) {
      return { label: t('user.status.locked'), type: 'warning' as const }
    }

    // 3. 正常状态映射
    const statusMap: Record<
      IdentityUserStatus,
      { label: string; type: 'success' | 'danger' | 'info' | 'warning' }
    > = {
      1: { label: t('user.status.active'), type: 'success' },
      2: { label: t('user.status.disabled'), type: 'danger' },
      3: { label: t('user.status.locked'), type: 'warning' }
    }
    return statusMap[row.status] || { label: t('user.status.unknown'), type: 'info' }
  }

  const resolveTenantLabel = (tenantId: string) => {
    const map = new Map(tenantOptions.value.map((item) => [String(item.value), item.label]))
    return map.get(String(tenantId)) || tenantId || '-'
  }

  const resolveAvatarText = (row: UserListItem) => {
    const name = row.displayName?.trim() || row.account?.trim() || ''
    return name ? name.slice(0, 1).toUpperCase() : ''
  }
  const resolveRoleLabel = (role: string) => roleLabelMap.value.get(role) || role

  const resolvePermissionLabel = (permission: string) =>
    permissionLabelMap.value.get(permission) || permission

  // 4. 表格与查询逻辑
  const buildColumns = (): ColumnOption<UserListItem>[] => {
    // 1. 构建基础列
    const columns: ColumnOption<UserListItem>[] = [
      { type: 'selection', width: 50 },
      { type: 'globalIndex', width: 60, label: t('table.column.index') },
      {
        prop: 'avatar',
        label: t('user.table.avatar'),
        width: 90,
        slotName: 'avatar',
        useSlot: true
      },
      { prop: 'account', label: t('user.table.account'), minWidth: 160 },
      { prop: 'displayName', label: t('user.table.displayName'), minWidth: 160 },
      { prop: 'phone', label: t('user.table.phone'), minWidth: 140 },
      { prop: 'email', label: t('user.table.email'), minWidth: 200 },
      {
        prop: 'roles',
        label: t('user.table.roles'),
        minWidth: 200,
        slotName: 'roles',
        useSlot: true
      },
      {
        prop: 'status',
        label: t('user.table.status'),
        minWidth: 120,
        slotName: 'status',
        useSlot: true
      },
      {
        prop: 'createdAt',
        label: t('user.table.createdAt'),
        minWidth: 160,
        formatter: (row: UserListItem) => formatDateTime(row.createdAt)
      },
      {
        prop: 'lastLoginAt',
        label: t('user.table.lastLoginAt'),
        minWidth: 160,
        formatter: (row: UserListItem) => formatDateTime(row.lastLoginAt)
      },
      {
        prop: 'actions',
        label: t('user.table.actions'),
        width: 260,
        fixed: 'right',
        slotName: 'actions',
        useSlot: true
      }
    ]

    // 2. 超级管理员追加租户列
    if (isSuperAdmin.value) {
      columns.splice(2, 0, {
        prop: 'tenantId',
        label: t('user.table.tenant'),
        minWidth: 180,
        slotName: 'tenant',
        useSlot: true
      })
    }

    return columns
  }

  const {
    columns,
    columnChecks,
    data,
    loading,
    pagination,
    searchParams,
    getData,
    refreshData,
    handleSizeChange,
    handleCurrentChange
  } = useTable<typeof fetchGetUserList, UserListItem>({
    core: {
      apiFn: fetchGetUserList,
      apiParams: { Page: 1, PageSize: 20 },
      paginationKey: { current: 'Page', size: 'PageSize' },
      immediate: false,
      columnsFactory: buildColumns
    }
  })

  const buildSearchParams = (): Api.SystemManage.UserSearchParams => {
    // 1. 提取筛选时间范围
    const createdRange = searchForm.value.createdRange || []
    const lastLoginRange = searchForm.value.lastLoginRange || []

    // 2. 组装查询参数
    return {
      TenantId: isSuperAdmin.value ? searchForm.value.tenantId : undefined,
      Keyword: searchForm.value.keyword?.trim() || undefined,
      Status: searchForm.value.status,
      RoleId: searchForm.value.roleId,
      CreatedAtFrom: createdRange.length === 2 ? createdRange[0] : undefined,
      CreatedAtTo: createdRange.length === 2 ? createdRange[1] : undefined,
      LastLoginFrom: lastLoginRange.length === 2 ? lastLoginRange[0] : undefined,
      LastLoginTo: lastLoginRange.length === 2 ? lastLoginRange[1] : undefined,
      IncludeDeleted: searchForm.value.includeDeleted
    }
  }

  const applySearchParams = (params: Api.SystemManage.UserSearchParams) => {
    // 1. 需要替换的查询字段
    const keys = [
      'TenantId',
      'Keyword',
      'Status',
      'RoleId',
      'CreatedAtFrom',
      'CreatedAtTo',
      'LastLoginFrom',
      'LastLoginTo',
      'IncludeDeleted'
    ]

    // 2. 清理旧参数
    const record = searchParams as Record<string, unknown>
    keys.forEach((key) => {
      delete record[key]
    })

    // 3. 写入新参数
    Object.assign(searchParams, params)
  }

  const handleSearch = () => {
    // 1. 应用搜索条件
    applySearchParams(buildSearchParams())

    // 2. 重新加载列表
    void getData()
  }

  const handleReset = () => {
    // 1. 重置搜索表单
    searchForm.value = {
      keyword: '',
      status: undefined,
      roleId: undefined,
      createdRange: [],
      lastLoginRange: [],
      includeDeleted: false,
      tenantId: undefined
    }
    // 2. 应用默认搜索参数
    applySearchParams(buildSearchParams())

    // 3. 重新加载列表
    void getData()
  }

  // 5. 选中行与跨页选择
  const tableRef = ref<InstanceType<typeof ArtTable> | null>(null)
  const selectedRows = ref<UserListItem[]>([])
  const selectedUserIds = ref<Set<string>>(new Set())

  const selectedCount = computed(() => selectedUserIds.value.size)

  const syncSelection = () => {
    // 1. 获取表格实例
    const table = tableRef.value?.elTableRef
    if (!table) return

    // 2. 恢复跨页选择状态
    table.clearSelection()
    data.value.forEach((row) => {
      if (selectedUserIds.value.has(row.userId)) {
        table.toggleRowSelection(row, true)
      }
    })
  }

  const handleSelectionChange = (selection: UserListItem[]) => {
    // 1. 更新当前页选择
    selectedRows.value = selection

    // 2. 计算跨页选择集合
    const nextSelected = new Set(selectedUserIds.value)
    const currentIds = new Set(data.value.map((row) => row.userId))
    const selectedIds = new Set(selection.map((row) => row.userId))

    // 3. 同步当前页勾选状态
    currentIds.forEach((id) => {
      if (selectedIds.has(id)) {
        nextSelected.add(id)
      } else {
        nextSelected.delete(id)
      }
    })

    selectedUserIds.value = nextSelected
  }

  watch(
    () => data.value,
    () => {
      nextTick(() => syncSelection())
    }
  )

  const clearSelection = () => {
    selectedRows.value = []
    selectedUserIds.value = new Set()
    tableRef.value?.elTableRef?.clearSelection?.()
  }

  // 6. 租户与角色数据加载
  const updateRoleLabelMap = (items: Api.TenantRole.RoleDto[]) => {
    const next = new Map(roleLabelMap.value)
    items.forEach((role) => {
      const label = role.name || role.code
      if (!label) return
      next.set(String(role.id), label)
      next.set(role.code, label)
    })
    roleLabelMap.value = next
  }

  const mapRoleOptions = (items: Api.TenantRole.RoleDto[]) => {
    updateRoleLabelMap(items)
    return items.map((role) => ({
      label: role.name || role.code,
      value: String(role.id)
    }))
  }

  const updatePermissionLabelMap = (items: PermissionDto[]) => {
    const next = new Map(permissionLabelMap.value)
    const stack = [...items]
    while (stack.length > 0) {
      const current = stack.pop()
      if (!current) continue
      const label = current.name || current.code
      if (label) {
        next.set(current.id, label)
        if (current.code) {
          next.set(current.code, label)
        }
      }
      if (current.children && current.children.length > 0) {
        stack.push(...current.children)
      }
    }
    permissionLabelMap.value = next
  }

  const loadTenantOptions = async () => {
    // 1. 非超管不加载租户选项
    if (!isSuperAdmin.value) return

    // 2. 拉取租户列表
    const result = await fetchGetTenantList({ Page: 1, PageSize: 200 })
    tenantOptions.value = Array.isArray(result?.items)
      ? result.items.map((tenant) => ({
          label: tenant.name,
          value: tenant.id
        }))
      : []
  }

  const loadRoleOptions = async (
    tenantId: string | undefined,
    target: typeof searchRoleOptions
  ) => {
    // 1. 缺少租户时清空列表
    if (!tenantId) {
      target.value = []
      return
    }

    // 2. 拉取并映射角色列表
    const result = await fetchGetTenantRoles(tenantId, { Page: 1, PageSize: 200 })
    target.value = Array.isArray(result?.items) ? mapRoleOptions(result.items) : []
  }

  const loadRoleLabels = async (tenantId?: string) => {
    if (!tenantId) return
    const result = await fetchGetTenantRoles(tenantId, { Page: 1, PageSize: 200 })
    if (Array.isArray(result?.items)) {
      updateRoleLabelMap(result.items)
    }
  }

  const loadPermissionLabels = async () => {
    const result = await fetchGetPermissionTree()
    if (Array.isArray(result)) {
      updatePermissionLabelMap(result)
    }
  }

  const loadSearchRoleOptions = async () => {
    // 1. 计算搜索租户
    const tenantId = isSuperAdmin.value ? searchForm.value.tenantId : currentTenantId.value

    // 2. 加载搜索角色
    await loadRoleOptions(tenantId, searchRoleOptions)
  }

  const loadDialogRoleOptions = async (tenantId?: string) => {
    // 1. 解析弹窗租户
    const resolvedTenantId = tenantId || currentTenantId.value

    // 2. 加载弹窗角色
    await loadRoleOptions(resolvedTenantId, dialogRoleOptions)
  }

  watch(
    () => searchForm.value.tenantId,
    (value) => {
      if (!isSuperAdmin.value) return
      searchForm.value.roleId = undefined
      void loadRoleOptions(value, searchRoleOptions)
    }
  )

  // 7. 弹窗与详情状态
  const dialogVisible = ref(false)
  const dialogType = ref<DialogType>('add')
  const dialogLoading = ref(false)
  const dialogUserData = ref<UserDetailDto | null>(null)
  const editingUserId = ref('')

  const dialogDefaultTenantId = computed(() => {
    if (!isSuperAdmin.value) return currentTenantId.value
    return searchForm.value.tenantId || tenantOptions.value[0]?.value?.toString() || ''
  })

  const detailVisible = ref(false)
  const detailLoading = ref(false)
  const detailData = ref<UserDetailDto | null>(null)
  const detailBaseRow = ref<UserListItem | null>(null)

  const resolveDetailStatus = computed(() => {
    if (!detailData.value) {
      return { label: '-', type: 'info' as const }
    }
    const base = detailBaseRow.value
    return resolveStatusInfo({
      status: detailData.value.status,
      isLocked: detailData.value.isLocked,
      isDeleted: base?.isDeleted
    })
  })

  // 8. 弹窗与详情操作
  const openCreateDialog = () => {
    dialogType.value = 'add'
    dialogUserData.value = null
    editingUserId.value = ''
    dialogVisible.value = true
    void loadDialogRoleOptions(dialogDefaultTenantId.value)
  }

  const openEditDialog = async (row: UserListItem) => {
    dialogLoading.value = true
    try {
      const detail = await fetchGetUserDetail(row.userId, row.isDeleted)
      dialogType.value = 'edit'
      dialogUserData.value = detail
      editingUserId.value = row.userId
      dialogVisible.value = true
      await loadDialogRoleOptions(detail.tenantId)
    } finally {
      dialogLoading.value = false
    }
  }

  const handleDialogTenantChange = (tenantId?: string) => {
    void loadDialogRoleOptions(tenantId)
  }

  const handleDialogSubmit = async (payload: UserDialogSubmitPayload) => {
    // 1. 打开提交加载态
    dialogLoading.value = true
    try {
      // 2. 新增用户
      if (payload.type === 'add') {
        await fetchCreateUser(payload.data)
        ElMessage.success(t('user.message.createSuccess'))
        dialogVisible.value = false
        refreshData()
        return
      }

      // 3. 校验编辑用户ID
      if (!editingUserId.value) {
        ElMessage.error(t('user.message.missingUserId'))
        return
      }

      // 4. 校验并发版本号
      if (!payload.data.rowVersion) {
        ElMessage.error(t('user.message.rowVersionMissing'))
        return
      }

      // 5. 提交更新
      await fetchUpdateUser(editingUserId.value, payload.data)
      ElMessage.success(t('user.message.updateSuccess'))
      dialogVisible.value = false
      refreshData()
    } catch (error) {
      // 1. 并发冲突提示
      if (isHttpError(error) && error.code === 409) {
        ElMessage.error(t('user.message.concurrencyConflict', { message: error.message }))
      }
    } finally {
      // 2. 关闭提交加载态
      dialogLoading.value = false
    }
  }

  const openDetail = async (row: UserListItem) => {
    detailVisible.value = true
    detailLoading.value = true
    detailBaseRow.value = row
    try {
      detailData.value = await fetchGetUserDetail(row.userId, row.isDeleted)
      void loadRoleLabels(detailData.value.tenantId)
    } finally {
      detailLoading.value = false
    }
  }

  // 9. 单行操作处理
  const isRowActionDisabled = (row: UserListItem, action: RowAction) => {
    // 1. 已删除仅允许恢复
    if (action === 'restore') return !row.isDeleted
    if (row.isDeleted) return true

    // 2. 启用/禁用状态判断
    if (action === 'enable') {
      return row.status === 1 && !row.isLocked
    }

    if (action === 'disable') {
      return row.status !== 1
    }

    // 3. 解锁仅限锁定态
    if (action === 'unlock') {
      return !row.isLocked
    }

    return false
  }

  const handleRowCommand = async (row: UserListItem, command: RowAction) => {
    // 1. 重置密码
    if (command === 'reset') {
      await handleResetPassword(row)
      return
    }

    // 2. 删除用户
    if (command === 'delete') {
      await handleDelete(row)
      return
    }

    // 3. 恢复用户
    if (command === 'restore') {
      await handleRestore(row)
      return
    }

    // 4. 启用用户
    if (command === 'enable') {
      await handleChangeStatus(row, 1)
      return
    }

    // 5. 禁用用户
    if (command === 'disable') {
      await handleChangeStatus(row, 2)
      return
    }

    // 6. 解锁用户
    if (command === 'unlock') {
      await handleChangeStatus(row, 1)
    }
  }

  const handleChangeStatus = async (row: UserListItem, status: IdentityUserStatus) => {
    // 1. 二次确认
    await ElMessageBox.confirm(
      t('user.message.statusConfirm', { name: row.displayName || row.account }),
      t('common.tips'),
      {
        type: 'warning',
        confirmButtonText: t('common.confirm'),
        cancelButtonText: t('common.cancel')
      }
    )

    // 2. 提交状态变更
    await fetchChangeUserStatus(row.userId, {
      status,
      tenantId: isSuperAdmin.value ? row.tenantId : undefined
    })

    // 3. 提示并刷新
    ElMessage.success(t('user.message.statusSuccess'))
    refreshData()
  }

  const handleDelete = async (row: UserListItem) => {
    // 1. 二次确认
    await ElMessageBox.confirm(
      t('user.message.deleteConfirm', { name: row.displayName || row.account }),
      t('common.tips'),
      {
        type: 'warning',
        confirmButtonText: t('common.confirm'),
        cancelButtonText: t('common.cancel')
      }
    )

    // 2. 执行删除
    await fetchDeleteUser(row.userId)

    // 3. 提示并刷新
    ElMessage.success(t('user.message.deleteSuccess'))
    refreshData()
  }

  const handleRestore = async (row: UserListItem) => {
    // 1. 二次确认
    await ElMessageBox.confirm(
      t('user.message.restoreConfirm', { name: row.displayName || row.account }),
      t('common.tips'),
      {
        type: 'warning',
        confirmButtonText: t('common.confirm'),
        cancelButtonText: t('common.cancel')
      }
    )

    // 2. 执行恢复
    await fetchRestoreUser(row.userId)

    // 3. 提示并刷新
    ElMessage.success(t('user.message.restoreSuccess'))
    refreshData()
  }

  const handleResetPassword = async (row: UserListItem) => {
    // 1. 二次确认
    await ElMessageBox.confirm(
      t('user.message.resetConfirm', { name: row.displayName || row.account }),
      t('common.tips'),
      {
        type: 'warning',
        confirmButtonText: t('common.confirm'),
        cancelButtonText: t('common.cancel')
      }
    )

    // 2. 执行重置
    const result = await fetchResetUserPassword(row.userId)

    // 3. 展示重置结果
    ElMessageBox.alert(
      t('user.message.resetToken', {
        token: result.token,
        expiresAt: formatDateTime(result.expiresAt)
      }),
      t('user.action.resetPassword'),
      {
        confirmButtonText: t('common.confirm')
      }
    )
  }

  // 10. 批量操作处理
  const handleBatchCommand = async (command: BatchAction) => {
    // 1. 校验选择数量
    const userIds = Array.from(selectedUserIds.value)
    if (userIds.length === 0) {
      ElMessage.warning(t('user.message.batchEmpty'))
      return
    }

    // 2. 校验批量上限
    if (userIds.length > 100) {
      ElMessage.error(t('user.message.batchLimit'))
      return
    }

    // 3. 构建批量操作映射
    const operationMap: Record<BatchAction, Api.SystemManage.IdentityUserBatchOperation> = {
      enable: 1,
      disable: 2,
      delete: 3,
      restore: 4,
      export: 5
    }

    // 4. 非导出操作需确认
    if (command !== 'export') {
      await ElMessageBox.confirm(
        t('user.message.batchConfirm', { count: userIds.length }),
        t('common.tips'),
        {
          type: 'warning',
          confirmButtonText: t('common.confirm'),
          cancelButtonText: t('common.cancel')
        }
      )
    }

    // 5. 执行批量操作
    const result = await fetchBatchUserOperation({
      tenantId: isSuperAdmin.value ? searchForm.value.tenantId : undefined,
      operation: operationMap[command],
      userIds
    })

    // 6. 导出操作直接输出文件
    if (command === 'export') {
      await exportUsersToCsv(result.exportItems)
      return
    }

    // 7. 处理批量结果
    if (result.failureCount > 0) {
      const failureText = result.failures
        .map((item) => `${item.userId}: ${item.reason}`)
        .slice(0, 5)
        .join('\n')

      ElMessageBox.alert(
        t('user.message.batchResult', {
          success: result.successCount,
          failure: result.failureCount,
          details: failureText || '-'
        }),
        t('common.tips'),
        { confirmButtonText: t('common.confirm') }
      )
    } else {
      ElMessage.success(t('user.message.batchSuccess', { count: result.successCount }))
    }

    // 8. 清理选择并刷新
    clearSelection()
    refreshData()
  }

  const exportUsersToCsv = async (rows: UserListItem[]) => {
    // 1. 构建表头
    const headers = [
      t('user.table.account'),
      t('user.table.displayName'),
      t('user.table.phone'),
      t('user.table.email'),
      t('user.table.status'),
      t('user.table.roles'),
      t('user.table.createdAt'),
      t('user.table.lastLoginAt')
    ].join(',')

    // 2. 拼接数据行
    const csvRows = rows.map((row) => {
      const statusLabel = resolveStatusInfo(row).label
      const roleText = row.roles.join('|')
      const values = [
        row.account,
        row.displayName,
        row.phone || '-',
        row.email || '-',
        statusLabel,
        roleText,
        formatDateTime(row.createdAt),
        formatDateTime(row.lastLoginAt)
      ]
      return values.map((value) => `"${value}"`).join(',')
    })

    // 3. 生成并下载文件
    const csv = [headers, ...csvRows].join('\n')
    const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8;' })
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-')

    FileSaver.saveAs(blob, `${t('user.export.fileName')}_${timestamp}.csv`)
    ElMessage.success(t('user.message.exportSuccess', { count: rows.length }))
  }

  // 11. 初始化加载
  const initPage = async () => {
    // 1. 加载租户与角色选项
    await loadTenantOptions()
    await loadSearchRoleOptions()
    await loadPermissionLabels()

    // 2. 初始化列表参数并拉取数据
    applySearchParams(buildSearchParams())
    await getData()
  }

  onMounted(() => {
    void initPage()
  })
</script>

<style scoped>
  .art-action-btn {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    min-width: 64px;
    padding: 6px 12px;
    font-size: 13px;
    line-height: 1;
    color: #333;
    cursor: pointer;
    background: #f5f7fa;
    border: 1px solid transparent;
    border-radius: 10px;
  }

  .art-action-btn .art-action-icon {
    display: flex;
    font-size: 16px;
  }

  .art-action-btn.primary {
    color: var(--el-color-primary);
    background: #ecf5ff;
    border-color: #d9ecff;
  }

  .art-action-btn.warning {
    color: var(--el-color-warning);
    background: #fdf6ec;
    border-color: #faecd8;
  }

  .art-action-btn.success {
    color: var(--el-color-success);
    background: #f0f9eb;
    border-color: #e1f3d8;
  }

  .art-action-btn.danger {
    color: var(--el-color-danger);
    background: #fef0f0;
    border-color: #fde2e2;
  }

  .art-action-btn.info {
    color: var(--el-color-info);
    background: #f4f4f5;
    border-color: #e9e9eb;
  }

  .art-action-btn:disabled {
    cursor: not-allowed;
    opacity: 0.6;
  }

  .art-action-btn:hover {
    filter: brightness(0.97);
    transition: all 0.15s ease;
  }

  .action-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
  }

  .dropdown-item {
    display: inline-flex;
    gap: 8px;
    align-items: center;
  }

  .dropdown-item.danger {
    color: var(--el-color-danger);
  }

  .dropdown-icon {
    font-size: 16px;
  }
</style>
