﻿<template>
  <div class="page-shell">
    <section class="page-card table-fill">
      <div class="page-toolbar">
        <n-form inline :show-label="false" class="toolbar-form">
          <n-form-item>
            <n-input v-model:value="queryForm.username" clearable placeholder="用户名" />
          </n-form-item>
          <n-form-item>
            <n-input v-model:value="queryForm.nickname" clearable placeholder="昵称" />
          </n-form-item>
          <n-form-item>
            <n-select
              v-model:value="queryForm.status"
              clearable
              placeholder="状态"
              :options="statusOptions"
              style="width: 140px"
            />
          </n-form-item>
          <n-form-item>
            <n-space>
              <n-button type="primary" @click="handleSearch">查询</n-button>
              <n-button @click="handleReset">重置</n-button>
            </n-space>
          </n-form-item>
        </n-form>
        <PermissionButton permission="system:user:create">
          <n-button type="primary" @click="openCreate">新增用户</n-button>
        </PermissionButton>
      </div>

      <div class="card-body card-body-fill table-fill">
        <n-data-table
          flex-height
          remote
          size="small"
          :columns="columns"
          :data="tableRows"
          :loading="usersQuery.isLoading.value"
          :pagination="pagination"
          :row-key="(row: UserListItem) => row.id"
          @update:page="onPageChange"
          @update:page-size="onPageSizeChange"
        />
      </div>
    </section>

    <n-modal
      v-model:show="detailModal.visible"
      preset="card"
      title="用户详情"
      :style="{ width: '920px', maxWidth: '92vw' }"
      :mask-closable="false"
      content-style="padding: 0; max-height: calc(85vh - 130px); overflow-y: auto"
    >
      <n-spin :show="detailModal.loading">
        <template v-if="detailUser">
          <div class="detail-shell">
            <div class="detail-header">
              <div>
                <div class="detail-name">{{ detailUser.nickname || detailUser.realName || detailUser.username }}</div>
                <div class="detail-username">{{ detailUser.username }}</div>
                <div class="detail-tags">
                  <n-tag :type="statusTagType(detailUser.status)" size="small" round>
                    {{ detailUser.statusLabel || statusLabel(detailUser.status) }}
                  </n-tag>
                  <n-tag v-if="detailUser.orgName || detailUser.orgCode" size="small" round>
                    {{ detailUser.orgName || detailUser.orgCode }}
                  </n-tag>
                </div>
              </div>
              <div class="detail-total">
                <span>角色数</span>
                <strong>{{ detailUser.roles?.length || 0 }}</strong>
              </div>
            </div>

            <div class="detail-section">
              <div class="detail-section-title">基础信息</div>
              <div class="detail-grid">
                <div v-for="item in baseDetailItems" :key="item.label" class="detail-item">
                  <span>{{ item.label }}</span>
                  <strong>{{ item.value }}</strong>
                </div>
              </div>
            </div>

            <div class="detail-section">
              <div class="detail-section-title">角色信息</div>
              <div class="role-tags">
                <n-tag
                  v-for="role in detailUser.roles"
                  :key="role.id"
                  size="small"
                  round
                  type="info"
                >
                  {{ role.name }}（{{ role.code }}）
                </n-tag>
                <span v-if="detailUser.roles.length === 0" class="empty-text">-</span>
              </div>
            </div>

            <div class="detail-section">
              <div class="detail-section-title">系统信息</div>
              <div class="detail-grid">
                <div v-for="item in systemDetailItems" :key="item.label" class="detail-item">
                  <span>{{ item.label }}</span>
                  <strong>{{ item.value }}</strong>
                </div>
              </div>
            </div>
          </div>
        </template>
      </n-spin>
    </n-modal>

    <n-modal
      v-model:show="editModal.visible"
      preset="card"
      :title="editModal.title"
      class="w-[560px]"
    >
      <n-form
        ref="editFormRef"
        :model="editForm"
        :rules="editRules"
        label-placement="left"
        label-width="90"
      >
        <n-form-item label="用户名" path="username">
          <n-input v-model:value="editForm.username" :disabled="editModal.mode === 'edit'" />
        </n-form-item>
        <n-form-item v-if="editModal.mode === 'create'" label="密码" path="password">
          <n-input v-model:value="editForm.password" type="password" show-password-on="click" />
        </n-form-item>
        <n-form-item label="昵称" path="nickname">
          <n-input v-model:value="editForm.nickname" />
        </n-form-item>
        <n-form-item label="姓名" path="realName">
          <n-input v-model:value="editForm.realName" />
        </n-form-item>
        <n-form-item label="手机号" path="phone">
          <n-input v-model:value="editForm.phone" />
        </n-form-item>
        <n-form-item label="邮箱" path="email">
          <n-input v-model:value="editForm.email" />
        </n-form-item>
        <n-form-item v-if="editModal.mode === 'create'" label="状态" path="status">
          <n-radio-group v-model:value="editForm.status">
            <n-radio-button value="ENABLED">启用</n-radio-button>
            <n-radio-button value="DISABLED">禁用</n-radio-button>
          </n-radio-group>
        </n-form-item>
      </n-form>
      <template #footer>
        <div class="flex justify-end gap-2">
          <n-button @click="editModal.visible = false">取消</n-button>
          <n-button type="primary" :loading="saveMutation.isPending.value" @click="handleSave"
            >保存</n-button
          >
        </div>
      </template>
    </n-modal>

    <n-modal v-model:show="passwordModal.visible" preset="card" title="重置密码" class="w-[460px]">
      <n-form
        ref="passwordFormRef"
        :model="passwordForm"
        :rules="passwordRules"
        label-placement="left"
        label-width="90"
      >
        <n-form-item label="新密码" path="password">
          <n-input v-model:value="passwordForm.password" type="password" show-password-on="click" />
        </n-form-item>
      </n-form>
      <template #footer>
        <div class="flex justify-end gap-2">
          <n-button @click="passwordModal.visible = false">取消</n-button>
          <n-button
            type="primary"
            :loading="passwordMutation.isPending.value"
            @click="handleResetPassword"
            >确认</n-button
          >
        </div>
      </template>
    </n-modal>

    <n-modal v-model:show="rolesModal.visible" preset="card" title="分配角色" class="w-[520px]">
      <n-form label-placement="left" label-width="90">
        <n-form-item label="角色">
          <n-select
            v-model:value="rolesModal.roleIds"
            multiple
            clearable
            filterable
            :options="roleOptions"
            placeholder="请选择角色"
          />
        </n-form-item>
      </n-form>
      <template #footer>
        <div class="flex justify-end gap-2">
          <n-button @click="rolesModal.visible = false">取消</n-button>
          <n-button
            type="primary"
            :loading="rolesMutation.isPending.value"
            @click="handleAssignRoles"
            >确认</n-button
          >
        </div>
      </template>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { computed, h, reactive, ref } from 'vue'
import type { DataTableColumns, FormInst, FormRules } from 'naive-ui'
import { NButton, NPopconfirm, NSpace, NSwitch, NTag, useMessage } from 'naive-ui'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import PermissionButton from '@/components/PermissionButton.vue'
import { useAuthStore } from '@/stores/auth'
import { statusLabel, statusTagType } from '@/utils/display'
import { renderPagePrefix } from '@/utils/pagination'
import {
  createUserApi,
  deleteUserApi,
  getUserDetailApi,
  listUsersApi,
  updateUserApi,
  updateUserPasswordApi,
  updateUserRolesApi,
  updateUserStatusApi
} from '@/api/system/user'
import { listRolesApi } from '@/api/system/role'
import type {
  CreateUserRequest,
  UpdateUserRequest,
  UserDetail,
  UserListItem
} from '@/types/system/user'

const message = useMessage()
const authStore = useAuthStore()
const queryClient = useQueryClient()

const queryForm = reactive({
  username: '',
  nickname: '',
  status: null as string | null
})

const pager = reactive({
  page: 1,
  pageSize: 10
})

const statusOptions = [
  { label: '启用', value: 'ENABLED' },
  { label: '禁用', value: 'DISABLED' }
]

const usersQuery = useQuery({
  queryKey: computed(() => ['system', 'users', { ...queryForm, ...pager }]),
  queryFn: () =>
    listUsersApi({
      page: pager.page,
      pageSize: pager.pageSize,
      username: queryForm.username || undefined,
      nickname: queryForm.nickname || undefined,
      status: queryForm.status || undefined
    })
})

const rolesQuery = useQuery({
  queryKey: ['system', 'roles', 'enabled'],
  queryFn: () => listRolesApi({ page: 1, pageSize: 200, status: 'ENABLED' })
})

const roleOptions = computed(() =>
  (rolesQuery.data.value?.items ?? []).map((role) => ({
    label: `${role.name} (${role.code})`,
    value: role.id
  }))
)

const tableRows = computed(() => usersQuery.data.value?.items ?? [])

const pagination = computed(() => ({
  page: pager.page,
  pageSize: pager.pageSize,
  itemCount: usersQuery.data.value?.total ?? 0,
  pageSizes: [10, 20, 50],
  showSizePicker: true,
  prefix: renderPagePrefix
}))

const editFormRef = ref<FormInst | null>(null)
const detailModal = reactive({
  visible: false,
  loading: false
})
const detailUser = ref<UserDetail | null>(null)

const baseDetailItems = computed(() => {
  const user = detailUser.value
  if (!user) return []
  return [
    { label: '用户ID', value: displayValue(user.id) },
    { label: '用户名', value: displayValue(user.username) },
    { label: '昵称', value: displayValue(user.nickname) },
    { label: '姓名', value: displayValue(user.realName) },
    { label: '手机号', value: displayValue(user.phone) },
    { label: '邮箱', value: displayValue(user.email) },
    { label: '组织', value: formatOrg(user) },
    { label: '状态', value: user.statusLabel || statusLabel(user.status) },
    { label: '头像', value: displayValue(user.avatar) }
  ]
})

const systemDetailItems = computed(() => {
  const user = detailUser.value
  if (!user) return []
  return [
    { label: 'Token版本', value: displayValue(user.tokenVersion) },
    { label: '数据版本', value: displayValue(user.version) },
    { label: '最后登录时间', value: displayValue(user.lastLoginAt) },
    { label: '最后登录IP', value: displayValue(user.lastLoginIp) },
    { label: '创建时间', value: displayValue(user.createdAt) },
    { label: '创建人', value: displayValue(user.createdBy) },
    { label: '更新时间', value: displayValue(user.updatedAt) },
    { label: '更新人', value: displayValue(user.updatedBy) },
    { label: '删除时间', value: displayValue(user.deletedAt) },
    { label: '删除人', value: displayValue(user.deletedBy) }
  ]
})

const editModal = reactive({
  visible: false,
  mode: 'create' as 'create' | 'edit',
  title: '新增用户',
  id: ''
})
const editForm = reactive({
  username: '',
  password: '',
  nickname: '',
  realName: '',
  phone: '',
  email: '',
  status: 'ENABLED'
})

const editRules: FormRules = {
  username: [{ required: true, message: '请输入用户名', trigger: ['input', 'blur'] }],
  password: [{ required: true, message: '请输入密码', trigger: ['input', 'blur'] }]
}

const saveMutation = useMutation({
  mutationFn: async () => {
    if (editModal.mode === 'create') {
      const payload: CreateUserRequest = {
        username: editForm.username.trim(),
        password: editForm.password,
        nickname: editForm.nickname.trim() || undefined,
        realName: editForm.realName.trim() || undefined,
        phone: editForm.phone.trim() || undefined,
        email: editForm.email.trim() || undefined,
        status: editForm.status
      }
      return createUserApi(payload)
    }
    const payload: UpdateUserRequest = {
      nickname: editForm.nickname.trim() || undefined,
      realName: editForm.realName.trim() || undefined,
      phone: editForm.phone.trim() || undefined,
      email: editForm.email.trim() || undefined
    }
    return updateUserApi(editModal.id, payload)
  },
  onSuccess: async () => {
    message.success('保存成功')
    editModal.visible = false
    await usersQuery.refetch()
  }
})

const deleteMutation = useMutation({
  mutationFn: (id: string) => deleteUserApi(id),
  onSuccess: async () => {
    message.success('删除成功')
    await usersQuery.refetch()
  }
})

const statusMutation = useMutation({
  mutationFn: ({ id, status }: { id: string; status: string }) =>
    updateUserStatusApi(id, { status }),
  onSuccess: async () => {
    message.success('状态更新成功')
    await usersQuery.refetch()
  }
})

const passwordFormRef = ref<FormInst | null>(null)
const passwordModal = reactive({
  visible: false,
  id: ''
})
const passwordForm = reactive({
  password: ''
})
const passwordRules: FormRules = {
  password: [{ required: true, message: '请输入新密码', trigger: ['input', 'blur'] }]
}

const passwordMutation = useMutation({
  mutationFn: () => updateUserPasswordApi(passwordModal.id, { password: passwordForm.password }),
  onSuccess: async () => {
    message.success('密码重置成功')
    passwordModal.visible = false
    passwordForm.password = ''
    await queryClient.invalidateQueries({ queryKey: ['system', 'users'] })
  }
})

const rolesModal = reactive({
  visible: false,
  id: '',
  roleIds: [] as string[]
})

const rolesMutation = useMutation({
  mutationFn: () => updateUserRolesApi(rolesModal.id, { roleIds: rolesModal.roleIds }),
  onSuccess: async () => {
    message.success('角色分配成功')
    rolesModal.visible = false
    await usersQuery.refetch()
  }
})

function onPageChange(page: number) {
  pager.page = page
}

function onPageSizeChange(pageSize: number) {
  pager.pageSize = pageSize
  pager.page = 1
}

function handleSearch() {
  pager.page = 1
  usersQuery.refetch()
}

function handleReset() {
  queryForm.username = ''
  queryForm.nickname = ''
  queryForm.status = null
  pager.page = 1
  usersQuery.refetch()
}

function resetEditForm() {
  editForm.username = ''
  editForm.password = ''
  editForm.nickname = ''
  editForm.realName = ''
  editForm.phone = ''
  editForm.email = ''
  editForm.status = 'ENABLED'
}

function openCreate() {
  editModal.mode = 'create'
  editModal.title = '新增用户'
  editModal.id = ''
  resetEditForm()
  editModal.visible = true
}

function displayValue(value: unknown) {
  if (value === null || value === undefined || value === '') return '-'
  return String(value)
}

function formatOrg(user: UserDetail) {
  if (user.orgName && user.orgCode) return `${user.orgName}（${user.orgCode}）`
  return user.orgName || user.orgCode || user.orgId || '-'
}

async function openDetail(row: UserListItem) {
  detailModal.visible = true
  detailModal.loading = true
  detailUser.value = null
  try {
    detailUser.value = await getUserDetailApi(row.id)
  } catch {
    message.error('查询用户详情失败')
  } finally {
    detailModal.loading = false
  }
}

async function openEdit(row: UserListItem) {
  editModal.mode = 'edit'
  editModal.title = `编辑用户 - ${row.username}`
  editModal.id = row.id
  const detail = await getUserDetailApi(row.id)
  editForm.username = detail.username
  editForm.password = ''
  editForm.nickname = detail.nickname ?? ''
  editForm.realName = detail.realName ?? ''
  editForm.phone = detail.phone ?? ''
  editForm.email = detail.email ?? ''
  editForm.status = detail.status
  editModal.visible = true
}

async function handleSave() {
  if (editModal.mode === 'create') {
    await editFormRef.value?.validate()
  } else {
    await editFormRef.value?.validate(
      (errors) => {
        if (!errors) return
        throw errors
      },
      (rule) => rule?.key !== 'password'
    )
  }
  await saveMutation.mutateAsync()
}

function openResetPassword(row: UserListItem) {
  passwordModal.id = row.id
  passwordForm.password = ''
  passwordModal.visible = true
}

async function handleResetPassword() {
  await passwordFormRef.value?.validate()
  await passwordMutation.mutateAsync()
}

async function openAssignRoles(row: UserListItem) {
  const detail = await getUserDetailApi(row.id)
  rolesModal.id = row.id
  rolesModal.roleIds = [...detail.roleIds]
  rolesModal.visible = true
}

async function handleAssignRoles() {
  await rolesMutation.mutateAsync()
}

function updateStatus(row: UserListItem, checked: boolean) {
  statusMutation.mutate({ id: row.id, status: checked ? 'ENABLED' : 'DISABLED' })
}

const columns = computed<DataTableColumns<UserListItem>>(() => [
  {
    title: '用户信息',
    key: 'username',
    minWidth: 180,
    render: (row) =>
      h('div', { class: 'leading-5' }, [
        h(
          'div',
          { class: 'font-medium text-slate-900' },
          row.nickname || row.realName || row.username
        ),
        h('div', { class: 'text-xs text-slate-500' }, row.username)
      ])
  },
  {
    title: '角色',
    key: 'roleCodes',
    minWidth: 180,
    render: (row) => (row.roleCodes.length > 0 ? row.roleCodes.join(', ') : '-')
  },
  {
    title: '状态',
    key: 'status',
    width: 120,
    render: (row) =>
      h(
        NTag,
        { type: statusTagType(row.status), size: 'small' },
        { default: () => statusLabel(row.status) }
      )
  },
  {
    title: '启停',
    key: 'statusSwitch',
    width: 110,
    render: (row) =>
      authStore.hasPermission('system:user:update')
        ? h(NSwitch, {
            size: 'small',
            value: row.status === 'ENABLED',
            onUpdateValue: (checked: boolean) => updateStatus(row, checked)
          })
        : '-'
  },
  {
    title: '操作',
    key: 'actions',
    width: 430,
    render: (row) =>
      h(
        NSpace,
        { size: 6 },
        {
          default: () => [
            h(
              NButton,
              {
                size: 'small',
                tertiary: true,
                type: 'info',
                class: 'action-btn',
                onClick: () => openDetail(row)
              },
              { default: () => '详情' }
            ),
            authStore.hasPermission('system:user:update')
              ? h(
                  NButton,
                  {
                    size: 'small',
                    tertiary: true,
                    type: 'primary',
                    class: 'action-btn',
                    onClick: () => openEdit(row)
                  },
                  { default: () => '编辑' }
                )
              : null,
            authStore.hasPermission('system:user:update')
              ? h(
                  NButton,
                  {
                    size: 'small',
                    tertiary: true,
                    type: 'warning',
                    class: 'action-btn',
                    onClick: () => openResetPassword(row)
                  },
                  { default: () => '重置密码' }
                )
              : null,
            authStore.hasPermission('system:role:assign')
              ? h(
                  NButton,
                  {
                    size: 'small',
                    tertiary: true,
                    type: 'info',
                    class: 'action-btn',
                    onClick: () => openAssignRoles(row)
                  },
                  { default: () => '分配角色' }
                )
              : null,
            authStore.hasPermission('system:user:delete')
              ? h(
                  NPopconfirm,
                  {
                    onPositiveClick: () => deleteMutation.mutate(row.id)
                  },
                  {
                    trigger: () =>
                      h(
                        NButton,
                        {
                          size: 'small',
                          tertiary: true,
                          type: 'error',
                          class: 'action-btn',
                          loading: deleteMutation.isPending.value
                        },
                        { default: () => '删除' }
                      ),
                    default: () => `确认删除用户 ${row.username} 吗？`
                  }
                )
              : null
          ]
        }
      )
  }
])
</script>

<style scoped>
.detail-shell {
  padding: 0 20px 20px;
}

.detail-header {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 0 16px;
  border-bottom: 1px solid #eef1f5;
}

.detail-name {
  color: #111827;
  font-size: 18px;
  font-weight: 600;
}

.detail-username {
  margin-top: 4px;
  color: #6b7280;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 13px;
}

.detail-tags {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.detail-total {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.detail-total span {
  color: #6b7280;
  font-size: 12px;
}

.detail-total strong {
  color: #111827;
  font-size: 24px;
  font-weight: 600;
}

.detail-section {
  padding-top: 18px;
}

.detail-section-title {
  margin-bottom: 12px;
  color: #111827;
  font-size: 15px;
  font-weight: 600;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.detail-item {
  padding: 14px;
  border: 1px solid #eef1f5;
  border-radius: 8px;
  background: #fafafa;
}

.detail-item span {
  display: block;
  margin-bottom: 6px;
  color: #6b7280;
  font-size: 12px;
}

.detail-item strong {
  color: #111827;
  font-size: 14px;
  font-weight: 500;
  word-break: break-all;
}

.role-tags {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.empty-text {
  color: #9ca3af;
  font-size: 13px;
}

@media (max-width: 960px) {
  .detail-grid {
    grid-template-columns: 1fr;
  }

  .detail-header {
    flex-direction: column;
    align-items: stretch;
  }

  .detail-total {
    align-items: flex-start;
  }
}
</style>
