<template>
  <div class="page-container">
    <el-card shadow="hover">
      <div class="toolbar">
        <div>
          <h2 class="page-title">终端用户管理</h2>
          <span class="text-muted">
            共 {{ users.length }} 个账号 · 在线会话 {{ totalSessions }} 个
          </span>
        </div>
        <div class="toolbar-actions">
          <el-input
            v-model="keyword"
            placeholder="搜索用户名"
            clearable
            style="width: 180px"
            @keyup.enter="load"
            @clear="load"
          />
          <el-select v-model="statusFilter" placeholder="全部状态" clearable style="width: 140px">
            <el-option label="正常" value="ACTIVE" />
            <el-option label="停用" value="SUSPENDED" />
            <el-option label="封禁" value="BANNED" />
          </el-select>
          <el-button :icon="'Refresh'" :loading="loading" @click="load">刷新</el-button>
          <el-button type="primary" :icon="'Plus'" @click="openCreate">添加用户</el-button>
        </div>
      </div>

      <el-table v-loading="loading" :data="users" stripe>
        <el-table-column prop="username" label="用户名" min-width="150">
          <template #default="{ row }">
            <span class="link-user" @click="openBindings(row)">{{ row.username }}</span>
            <el-tag v-if="row.deviceCount > 0" type="info" size="small" style="margin-left: 6px">
              {{ row.deviceCount }} 台设备
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="userId" label="用户 ID" min-width="200" show-overflow-tooltip />
        <el-table-column label="状态" width="140">
          <template #default="{ row }">
            <el-tag :type="statusTagType(row.status)" effect="dark" size="small">
              {{ statusText(row.status) }}
            </el-tag>
            <el-tooltip v-if="row.statusReason" :content="row.statusReason" placement="top">
              <el-icon class="reason-icon"><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="双因子" width="90">
          <template #default="{ row }">
            <el-tag :type="row.totpEnabled ? 'success' : 'info'" size="small">
              {{ row.totpEnabled ? '已启用' : '未启用' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="在线会话" width="100" align="center">
          <template #default="{ row }">
            <el-button
              v-if="row.activeSessions > 0"
              link
              type="primary"
              @click="openSessions(row)"
            >
              {{ row.activeSessions }}
            </el-button>
            <span v-else class="text-muted">0</span>
          </template>
        </el-table-column>
        <el-table-column label="最后登录" min-width="170">
          <template #default="{ row }">{{ fmtTime(row.lastLoginAt) }}</template>
        </el-table-column>
        <el-table-column label="创建时间" min-width="170">
          <template #default="{ row }">{{ fmtTime(row.createdAt) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="230" fixed="right">
          <template #default="{ row }">
            <span class="action-group">
            <el-button
              v-if="row.status === 'ACTIVE'"
              link
              type="warning"
              @click="handleBan(row)"
            >
              禁用
            </el-button>
            <el-button v-else link type="success" @click="handleUnban(row)">启用</el-button>
            <el-button link type="primary" @click="handleKick(row)">下线</el-button>
            <el-dropdown trigger="click" @command="(cmd: string) => handleCommand(cmd, row)">
              <el-button link type="info">更多</el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item command="bindings">查看绑定设备</el-dropdown-item>
                  <el-dropdown-item command="sessions">查看会话</el-dropdown-item>
                  <el-dropdown-item command="reset">重置密码</el-dropdown-item>
                  <el-dropdown-item command="delete" divided>删除账号</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            </span>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 添加用户 -->
    <el-dialog v-model="createVisible" title="添加用户" width="440px">
      <el-form ref="createFormRef" :model="createForm" :rules="createRules" label-width="80px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="createForm.username" placeholder="3-32 位字母数字下划线" />
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="createForm.password" type="password" show-password />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="createVisible = false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="submitCreate">确定</el-button>
      </template>
    </el-dialog>

    <!-- 重置密码 -->
    <el-dialog v-model="resetVisible" title="重置密码" width="420px">
      <el-alert
        :title="`将重置账号「${current?.username}」的密码，该账号所有登录会话会被强制下线`"
        type="warning"
        :closable="false"
        show-icon
        style="margin-bottom: 16px"
      />
      <el-input v-model="newPassword" type="password" placeholder="请输入新密码" show-password />
      <template #footer>
        <el-button @click="resetVisible = false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="submitReset">确定</el-button>
      </template>
    </el-dialog>

    <!-- 会话列表 -->
    <el-dialog v-model="sessionsVisible" :title="`「${current?.username}」的登录会话`" width="720px">
      <el-table v-loading="sessionLoading" :data="sessions" stripe size="small">
        <el-table-column prop="sessionId" label="会话 ID" min-width="180" show-overflow-tooltip />
        <el-table-column prop="ip" label="IP" width="130">
          <template #default="{ row }">{{ row.ip || '—' }}</template>
        </el-table-column>
        <el-table-column label="登录时间" min-width="160">
          <template #default="{ row }">{{ fmtTime(row.createdAt) }}</template>
        </el-table-column>
        <el-table-column label="最后活跃" min-width="160">
          <template #default="{ row }">{{ fmtTime(row.lastSeenAt) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="80" fixed="right">
          <template #default="{ row }">
            <el-button link type="danger" @click="handleKickSession(row)">踢出</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>

    <!-- 绑定关系（点击用户名查看该用户绑定的终端设备） -->
    <el-dialog v-model="bindingsVisible" :title="`「${bindingUser?.username}」绑定的终端设备`" width="760px">
      <el-table v-loading="bindingLoading" :data="userBindings" stripe size="small" empty-text="该用户暂未绑定任何终端设备">
        <el-table-column prop="deviceUid" label="设备 ID" min-width="200" show-overflow-tooltip />
        <el-table-column label="别名" min-width="140">
          <template #default="{ row }">{{ row.alias || '—' }}</template>
        </el-table-column>
        <el-table-column label="角色" width="100">
          <template #default="{ row }">
            <el-tag :type="row.role === 'OWNER' ? 'primary' : 'info'" size="small">
              {{ row.role === 'OWNER' ? '所有者' : '成员' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="100">
          <template #default="{ row }">
            <el-tag :type="row.status === 'ACTIVE' ? 'success' : 'danger'" size="small">
              {{ row.status === 'ACTIVE' ? '有效' : '已撤销' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="在线" width="90" align="center">
          <template #default="{ row }">
            <el-tag :type="row.online ? 'success' : 'info'" size="small" effect="dark">
              {{ row.online ? '在线' : '离线' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="绑定时间" min-width="170">
          <template #default="{ row }">{{ fmtTime(row.boundAt) }}</template>
        </el-table-column>
      </el-table>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { InfoFilled } from '@element-plus/icons-vue';
import type { FormInstance, FormRules } from 'element-plus';
import {
  getUsers,
  createUser,
  deleteUser,
  resetUserPassword,
  banUser,
  unbanUser,
  kickUser,
  getUserSessions,
  getUserBindings,
  kickSession,
} from '@/api/admin';
import type { AccountStatus, UserAccountView, UserSessionView, UserBindingView } from '@/api/admin';

const users = ref<UserAccountView[]>([]);
const loading = ref(false);
const submitting = ref(false);
const keyword = ref('');
const statusFilter = ref('');
const current = ref<UserAccountView | null>(null);

const totalSessions = computed(() =>
  users.value.reduce((sum, u) => sum + (u.activeSessions || 0), 0),
);

async function load() {
  loading.value = true;
  try {
    users.value = await getUsers({
      keyword: keyword.value || undefined,
      status: statusFilter.value || undefined,
    });
  } finally {
    loading.value = false;
  }
}

watch(statusFilter, load);

// ---------- 添加用户 ----------
const createVisible = ref(false);
const createFormRef = ref<FormInstance>();
const createForm = ref({ username: '', password: '' });
const createRules: FormRules = {
  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 3, max: 32, message: '长度需为 3-32 位', trigger: 'blur' },
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 8, message: '密码至少 8 位', trigger: 'blur' },
  ],
};

function openCreate() {
  createForm.value = { username: '', password: '' };
  createVisible.value = true;
}

async function submitCreate() {
  const valid = await createFormRef.value?.validate().catch(() => false);
  if (!valid) return;
  submitting.value = true;
  try {
    const resp = await createUser(createForm.value);
    if (resp.success) {
      ElMessage.success('账号创建成功');
      createVisible.value = false;
      await load();
    } else {
      ElMessage.error(resp.message || '创建失败');
    }
  } finally {
    submitting.value = false;
  }
}

// ---------- 禁用 / 启用 / 下线 ----------
async function handleBan(row: UserAccountView) {
  const input = await ElMessageBox.prompt('请输入禁用原因', `禁用账号「${row.username}」`, {
    inputPlaceholder: '例如：违规操作',
    confirmButtonText: '确定禁用',
    cancelButtonText: '取消',
    type: 'warning',
  }).catch(() => null);
  if (!input) return;
  await banUser(row.userId, input.value || '管理员操作');
  ElMessage.success('账号已禁用');
  await load();
}

async function handleUnban(row: UserAccountView) {
  await unbanUser(row.userId);
  ElMessage.success('账号已启用');
  await load();
}

async function handleKick(row: UserAccountView) {
  const ok = await ElMessageBox.confirm(
    `确定强制账号「${row.username}」全端下线？该账号需要重新登录。`,
    '强制下线',
    { type: 'warning', confirmButtonText: '确定', cancelButtonText: '取消' },
  ).catch(() => false);
  if (!ok) return;
  await kickUser(row.userId, '管理员强制下线');
  ElMessage.success('已强制下线');
  await load();
}

async function handleDelete(row: UserAccountView) {
  const ok = await ElMessageBox.confirm(
    `确定删除账号「${row.username}」？该操作不可恢复，其全部会话将被清除。`,
    '删除账号',
    { type: 'error', confirmButtonText: '确定删除', cancelButtonText: '取消' },
  ).catch(() => false);
  if (!ok) return;
  await deleteUser(row.userId);
  ElMessage.success('账号已删除');
  await load();
}

// ---------- 重置密码 ----------
const resetVisible = ref(false);
const newPassword = ref('');

function openReset(row: UserAccountView) {
  current.value = row;
  newPassword.value = '';
  resetVisible.value = true;
}

async function submitReset() {
  if (!newPassword.value || newPassword.value.length < 8) {
    ElMessage.warning('密码至少 8 位');
    return;
  }
  submitting.value = true;
  try {
    const resp = await resetUserPassword(current.value!.userId, newPassword.value);
    if (resp.success) {
      ElMessage.success('密码已重置');
      resetVisible.value = false;
      await load();
    } else {
      ElMessage.error(resp.message || '重置失败');
    }
  } catch {
    // 错误提示已由 request 响应拦截器统一弹出，这里仅吞掉异常，
    // 避免未捕获的 Promise rejection，并保证弹窗保持打开以便重试。
  } finally {
    submitting.value = false;
  }
}

// ---------- 会话 ----------
const sessionsVisible = ref(false);
const sessions = ref<UserSessionView[]>([]);
const sessionLoading = ref(false);

async function openSessions(row: UserAccountView) {
  current.value = row;
  sessionsVisible.value = true;
  sessionLoading.value = true;
  try {
    sessions.value = await getUserSessions(row.userId);
  } finally {
    sessionLoading.value = false;
  }
}

// ---------- 绑定关系（点击用户名查看该用户绑定的终端设备） ----------
const bindingsVisible = ref(false);
const bindingUser = ref<UserAccountView | null>(null);
const userBindings = ref<UserBindingView[]>([]);
const bindingLoading = ref(false);

async function openBindings(row: UserAccountView) {
  bindingUser.value = row;
  bindingsVisible.value = true;
  bindingLoading.value = true;
  try {
    userBindings.value = await getUserBindings(row.userId);
  } catch {
    userBindings.value = [];
    ElMessage.error('加载绑定关系失败');
  } finally {
    bindingLoading.value = false;
  }
}

async function handleKickSession(row: UserSessionView) {
  await kickSession(row.sessionId);
  ElMessage.success('会话已踢出');
  if (current.value) await openSessions(current.value);
  await load();
}

function handleCommand(cmd: string, row: UserAccountView) {
  if (cmd === 'bindings') openBindings(row);
  else if (cmd === 'sessions') openSessions(row);
  else if (cmd === 'reset') openReset(row);
  else if (cmd === 'delete') handleDelete(row);
}

function statusText(status: AccountStatus) {
  return { ACTIVE: '正常', SUSPENDED: '停用', BANNED: '封禁' }[status] || status;
}

function statusTagType(status: AccountStatus) {
  return { ACTIVE: 'success', SUSPENDED: 'warning', BANNED: 'danger' }[status] || 'info';
}

function fmtTime(ts: number | null) {
  return ts ? new Date(ts).toLocaleString('zh-CN') : '—';
}

onMounted(load);
</script>

<style scoped>
.action-group {
  display: flex;
  align-items: center;
  gap: 12px;
}
.link-user {
  color: var(--el-color-primary);
  cursor: pointer;
  font-weight: 500;
}
.link-user:hover {
  text-decoration: underline;
}
.page-title {
  margin: 0 0 4px;
  font-size: 20px;
}
.toolbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 16px;
  flex-wrap: wrap;
  gap: 8px;
}
.toolbar-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}
.reason-icon {
  margin-left: 6px;
  color: var(--el-color-warning);
  vertical-align: middle;
}
</style>
