<template>
  <el-card>
    <template #header>
      <div class='flex justify-between items-center'>
        <span class='font-700'>用户管理</span>
        <div class='btn-gap-8' v-if='hasPermission("platform.users.manage")'>
          <el-button type='warning' :disabled='selectedUserIds.length === 0' @click='openBatchAssignDialog'>批量设置用户组和权限</el-button>
          <el-button type='success' :loading='importing' @click='openImportDialog'>批量导入</el-button>
          <el-button type='primary' @click='openCreate'>新增用户</el-button>
        </div>
      </div>
    </template>

    <el-table :data='rows' v-loading='loading' @sort-change='handleSortChange' @selection-change='handleSelectionChange'>
      <el-table-column v-if='hasPermission("platform.users.manage")' type='selection' width='48' />
      <el-table-column prop='id' label='ID' width='70' sortable='custom' />
      <el-table-column prop='nickname' label='昵称' min-width='130' sortable='custom' />
      <el-table-column prop='email' label='邮箱' min-width='180' sortable='custom' />
      <el-table-column prop='phone' label='手机号' min-width='140' sortable='custom' />
      <el-table-column label='角色' min-width='160'>
        <template #default='{ row }'>{{ (row.roles || []).map((r:any) => r.name).join(', ') || '-' }}</template>
      </el-table-column>
      <el-table-column label='直授权限' min-width='220'>
        <template #default='{ row }'>{{ (row.permissions || []).map((p:any) => p.name).join(', ') || '-' }}</template>
      </el-table-column>
      <el-table-column v-if='hasPermission("platform.users.manage")' label='操作' width='220'>
        <template #default='{ row }'>
          <div class='btn-gap-8 btn-gap-8--nowrap'>
            <el-button size='small' @click='openEdit(row)'>编辑</el-button>
            <el-button size='small' type='warning' @click='openPermissionDialog(row)'>分配权限</el-button>
            <el-button size='small' type='danger' @click='removeRow(row)'>删除</el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      class='mt-4'
      layout='total, sizes, prev, pager, next'
      :total='total'
      :current-page='page'
      :page-size='perPage'
      :page-sizes='[10, 20, 50, 100]'
      @current-change='handlePageChange'
      @size-change='handleSizeChange'
    />

    <el-dialog v-model='dialogVisible' :title='editingId ? "编辑用户" : "新增用户"' width='560px'>
      <el-form :model='form' label-width='95px'>
        <el-form-item label='昵称'><el-input v-model='form.nickname' /></el-form-item>
        <el-form-item label='邮箱'><el-input v-model='form.email' /></el-form-item>
        <el-form-item label='手机号'><el-input v-model='form.phone' /></el-form-item>
        <el-form-item label='密码'><el-input v-model='form.password' type='password' show-password /></el-form-item>
        <el-form-item label='需更改密码'><el-switch v-model='form.force_password_change' /></el-form-item>
        <el-form-item label='角色'>
          <el-select v-model='form.role_ids' multiple collapse-tags>
            <el-option v-for='item in roleOptions' :key='item.id' :label='item.name' :value='item.id' />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click='dialogVisible = false'>取消</el-button>
        <el-button type='primary' :loading='saving' @click='submit'>提交</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model='permissionDialogVisible' title='用户直授权限分配' width='92vw' top='4vh'>
      <div class='permission-panel-wrap'>
        <el-cascader-panel v-model='selectedPermissionNodes' :options='permissionCascader' :props='cascaderProps' class='permission-panel' />
      </div>
      <template #footer>
        <el-button @click='permissionDialogVisible = false'>取消</el-button>
        <el-button type='primary' :loading='savingPermissions' @click='submitPermissions'>保存权限</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model='batchAssignDialogVisible' title='批量设置用户组和用户权限' width='760px'>
      <el-alert type='info' :closable='false' show-icon>
        <template #default>已选择 {{ selectedUserIds.length }} 个用户，提交后将覆盖这些用户的角色与直授权限。</template>
      </el-alert>
      <el-form :model='batchAssignForm' label-width='90px' class='mt-4'>
        <el-form-item label='用户组'>
          <el-select v-model='batchAssignForm.role_ids' multiple collapse-tags clearable class='w-full' placeholder='请选择用户组'>
            <el-option v-for='item in roleOptions' :key='item.id' :label='item.name' :value='item.id' />
          </el-select>
        </el-form-item>
        <el-form-item label='用户权限'>
          <div class='permission-panel-wrap'>
            <el-cascader-panel v-model='batchAssignPermissionNodes' :options='permissionCascader' :props='cascaderProps' class='permission-panel' />
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click='batchAssignDialogVisible = false'>取消</el-button>
        <el-button type='primary' :loading='batchAssigning' @click='submitBatchAssign'>提交</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model='importDialogVisible' title='批量导入用户' width='620px'>
      <el-alert type='info' show-icon :closable='false'>
        <template #default>
          仅支持 `xlsx`。表头示例：`nickname,email,phone,password,role_ids,force_password_change`，其中 `role_ids` 可选，多个用英文逗号分隔。
        </template>
      </el-alert>
      <el-upload
        class='mt-4'
        drag
        :auto-upload='false'
        :show-file-list='true'
        :limit='1'
        :on-change='handleImportFileChange'
        :on-remove='handleImportFileRemove'
        :accept="'.xlsx'"
      >
        <el-icon class='el-icon--upload'><upload-filled /></el-icon>
        <div class='el-upload__text'>拖拽文件到这里，或<em>点击选择</em></div>
      </el-upload>

      <div v-if='importResult' class='mt-4'>
        <el-alert
          :type='importResult.error_count > 0 ? "warning" : "success"'
          :closable='false'
          :title='`导入完成：成功 ${importResult.created_count} 条，跳过 ${importResult.skipped_count} 条`'
        />
        <el-table v-if='importResult.errors?.length' :data='importResult.errors' class='mt-3' max-height='220'>
          <el-table-column prop='line' label='行号' width='90' />
          <el-table-column prop='message' label='错误信息' min-width='360' />
        </el-table>
      </div>

      <template #footer>
        <el-button @click='downloadImportTemplate'>下载导入模板</el-button>
        <el-button @click='importDialogVisible = false'>关闭</el-button>
        <el-button type='primary' :loading='importing' @click='submitImport'>开始导入</el-button>
      </template>
    </el-dialog>
  </el-card>
</template>

<script setup lang='ts'>
import { UploadFilled } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { computed, onMounted, reactive, ref } from 'vue'
import { permissionsApi } from '@/api/permissions'
import { rolesApi } from '@/api/roles'
import { usersApi } from '@/api/users'
import { buildPermissionCascader, extractPermissionIds } from '@/composables/permission-tree'
import { useAuthStore } from '@/stores/auth'

const authStore = useAuthStore()
const { hasPermission } = authStore

const loading = ref(false)
const saving = ref(false)
const savingPermissions = ref(false)
const dialogVisible = ref(false)
const permissionDialogVisible = ref(false)
const importDialogVisible = ref(false)
const batchAssignDialogVisible = ref(false)
const editingId = ref<number | null>(null)
const permissionTargetUserId = ref<number | null>(null)
const importing = ref(false)
const batchAssigning = ref(false)
const selectedUserIds = ref<number[]>([])
const rows = ref<any[]>([])
const roleOptions = ref<any[]>([])
const permissionOptions = ref<any[]>([])
const selectedPermissionNodes = ref<Array<number | string>>([])
const batchAssignPermissionNodes = ref<Array<number | string>>([])
const importFile = ref<File | null>(null)
const importResult = ref<{ created_count: number; skipped_count: number; error_count: number; errors: Array<{ line: number; message: string }> } | null>(null)
const total = ref(0)
const page = ref(1)
const perPage = ref(20)
const sortBy = ref('created_at')
const sortOrder = ref<'asc' | 'desc'>('desc')

const form = reactive<any>({ nickname: '', email: '', phone: '', password: '', force_password_change: false, role_ids: [] })
const batchAssignForm = reactive<{ role_ids: number[] }>({ role_ids: [] })
const cascaderProps = { multiple: true, emitPath: false, checkStrictly: false }
const permissionCascader = computed(() => buildPermissionCascader(permissionOptions.value))

async function fetchList(): Promise<void> {
  loading.value = true
  try {
    const response: any = await usersApi.list({
      page: page.value,
      per_page: perPage.value,
      sort_by: sortBy.value,
      sort_order: sortOrder.value,
    })
    const list = response.data.data || []
    rows.value = await Promise.all(list.map(async (item: any) => (await usersApi.detail(item.id) as any).data))
    selectedUserIds.value = []
    total.value = response.data.total || 0
  } finally {
    loading.value = false
  }
}

async function fetchOptions(): Promise<void> {
  try {
    const [rolesResponse, permissionsResponse]: any = await Promise.all([
      rolesApi.list({ page: 1, per_page: 100 }),
      permissionsApi.list({ page: 1, per_page: 200 }),
    ])
    roleOptions.value = rolesResponse.data.data || []
    permissionOptions.value = permissionsResponse.data.data || []
  } catch (error: any) {
    roleOptions.value = []
    permissionOptions.value = []
    const first = error?.errors ? (Object.values(error.errors)[0] as string[])?.[0] : null
    ElMessage.error(first || error?.message || '加载用户组选项失败')
  }
}

function handlePageChange(nextPage: number): void {
  page.value = nextPage
  fetchList()
}

function handleSizeChange(nextSize: number): void {
  perPage.value = nextSize
  page.value = 1
  fetchList()
}

function handleSortChange(payload: { prop: string, order: 'ascending' | 'descending' | null }): void {
  if (!payload.prop || !payload.order) {
    sortBy.value = 'created_at'
    sortOrder.value = 'desc'
    page.value = 1
    fetchList()
    return
  }

  sortBy.value = payload.prop
  sortOrder.value = payload.order === 'ascending' ? 'asc' : 'desc'
  page.value = 1
  fetchList()
}

function openCreate(): void {
  editingId.value = null
  Object.assign(form, { nickname: '', email: '', phone: '', password: '', force_password_change: false, role_ids: [] })
  dialogVisible.value = true
}

function openEdit(row: any): void {
  editingId.value = row.id
  Object.assign(form, {
    nickname: row.nickname,
    email: row.email,
    phone: row.phone,
    password: '',
    force_password_change: Boolean(row.force_password_change),
    role_ids: (row.roles || []).map((item: any) => item.id),
  })
  dialogVisible.value = true
}

function openPermissionDialog(row: any): void {
  permissionTargetUserId.value = row.id
  selectedPermissionNodes.value = (row.permissions || []).map((item: any) => item.id)
  permissionDialogVisible.value = true
}

async function submit(): Promise<void> {
  saving.value = true
  try {
    const payload: any = { ...form }
    if (!payload.password) {
      delete payload.password
    }

    if (editingId.value) {
      await usersApi.update(editingId.value, payload)
      ElMessage.success('更新成功')
    } else {
      await usersApi.create(payload)
      ElMessage.success('创建成功')
    }

    dialogVisible.value = false
    await fetchList()
  } catch (error: any) {
    const first = error?.errors ? (Object.values(error.errors)[0] as string[])?.[0] : null
    ElMessage.error(first || error?.message || '提交失败')
  } finally {
    saving.value = false
  }
}

async function submitPermissions(): Promise<void> {
  if (!permissionTargetUserId.value) {
    return
  }

  savingPermissions.value = true
  try {
    const permissionIds = extractPermissionIds(selectedPermissionNodes.value)
    await usersApi.syncPermissions(permissionTargetUserId.value, permissionIds)
    ElMessage.success('权限更新成功')
    permissionDialogVisible.value = false
    await fetchList()
  } finally {
    savingPermissions.value = false
  }
}

async function removeRow(row: any): Promise<void> {
  await ElMessageBox.confirm(`确认删除用户 ${row.nickname} 吗？`, '提示', { type: 'warning' })
  await usersApi.remove(row.id)
  ElMessage.success('删除成功')
  await fetchList()
}

function openImportDialog(): void {
  importFile.value = null
  importResult.value = null
  importDialogVisible.value = true
}

function openBatchAssignDialog(): void {
  if (selectedUserIds.value.length === 0) {
    ElMessage.warning('请先勾选用户')
    return
  }
  batchAssignForm.role_ids = []
  batchAssignPermissionNodes.value = []
  batchAssignDialogVisible.value = true
}

function handleImportFileChange(file: any): void {
  importFile.value = file?.raw || null
}

function handleImportFileRemove(): void {
  importFile.value = null
}

async function submitImport(): Promise<void> {
  if (!importFile.value) {
    ElMessage.warning('请先选择导入文件')
    return
  }

  importing.value = true
  try {
    const response: any = await usersApi.importUsers(importFile.value)
    importResult.value = {
      created_count: Number(response?.data?.created_count || 0),
      skipped_count: Number(response?.data?.skipped_count || 0),
      error_count: Array.isArray(response?.data?.errors) ? response.data.errors.length : 0,
      errors: response?.data?.errors || [],
    }
    ElMessage.success('批量导入已执行')
    await fetchList()
    await fetchOptions()
  } catch (error: any) {
    const first = error?.errors ? (Object.values(error.errors)[0] as string[])?.[0] : null
    ElMessage.error(first || error?.message || '导入失败')
  } finally {
    importing.value = false
  }
}

async function downloadImportTemplate(): Promise<void> {
  try {
    const blob: Blob = await usersApi.downloadImportTemplate() as any
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = 'users_import_template.xlsx'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  } catch (_error) {
    ElMessage.error('下载模板失败')
  }
}

function handleSelectionChange(selection: any[]): void {
  selectedUserIds.value = selection
    .map((item: any) => Number(item.id || 0))
    .filter((id: number) => id > 0)
}

async function submitBatchAssign(): Promise<void> {
  if (selectedUserIds.value.length === 0) {
    ElMessage.warning('请先勾选用户')
    return
  }
  batchAssigning.value = true
  try {
    await usersApi.syncBatchAssignments({
      user_ids: selectedUserIds.value,
      role_ids: batchAssignForm.role_ids,
      permission_ids: extractPermissionIds(batchAssignPermissionNodes.value),
    })
    ElMessage.success('批量设置成功')
    batchAssignDialogVisible.value = false
    await fetchList()
  } catch (error: any) {
    const first = error?.errors ? (Object.values(error.errors)[0] as string[])?.[0] : null
    ElMessage.error(first || error?.message || '批量设置失败')
  } finally {
    batchAssigning.value = false
  }
}

onMounted(async () => {
  await Promise.all([fetchOptions(), fetchList()])
})
</script>

<style scoped>
:deep(.el-dialog) { max-width: 1000px; }
.permission-panel-wrap { width: 100%; overflow: hidden; }
.permission-panel { width: 100%; height: 40vh; min-height: 420px; }
:deep(.permission-panel .el-cascader-menu) { width: 260px; min-width: 260px; }
:deep(.permission-panel .el-cascader-menu__wrap) { height: 100%; overflow-y: auto; overflow-x: hidden; }
:deep(.permission-panel .el-cascader-node__label) {
  white-space: nowrap;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.35;
}
:deep(.permission-panel .el-cascader-menu__list) { width: 100%; }
:deep(.permission-panel .el-cascader-node) { width: 100%; }
:deep(.permission-panel .el-cascader-panel) { height: 100%; }
</style>
