import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { PrismaService } from '@/core/database/prisma/prisma.service';
import { createTestApp } from '../../helpers/app.helper';
import { cleanupDatabase } from '../../helpers/cleanup.helper';
import {
  assignRoleToUser,
  createAdminUser,
  createTestUser,
} from '../../helpers/factories';

/**
 * Meeting-attendance · Users Controller L1 集成测试
 *
 * 覆盖 10 个 endpoint × HTTP 行为 + 鉴权 + 核心业务规则：
 *   GET    /meeting-attendance/users                  （列表，需 admin/manager）
 *   POST   /meeting-attendance/users                  （指派角色，需 admin/manager）
 *   GET    /meeting-attendance/users/search            （搜索，需任意会议用户）
 *   GET    /meeting-attendance/users/import            （下载 CSV 模板，需 admin/manager）
 *   POST   /meeting-attendance/users/import            （批量导入，需 admin/manager）
 *   GET    /meeting-attendance/users/:id               （用户详情，自己或 admin/manager）
 *   PUT    /meeting-attendance/users/:id               （更新角色，需 admin/manager）
 *   DELETE /meeting-attendance/users/:id               （禁用，需 admin/manager，不能自禁）
 *   POST   /meeting-attendance/users/:id/reset-password（重置密码，固定返回 400）
 *   DELETE /meeting-attendance/users/:id/permanent     （永久删除，需 admin/manager，不能自删）
 *
 * 关联工单 #341 · Batch 100% 覆盖
 */
describe('Meeting-attendance · Users API', () => {
  let app: INestApplication;
  let prisma: PrismaService;

  beforeAll(async () => {
    process.env.NODE_ENV = 'test';
    app = await createTestApp();
    prisma = app.get<PrismaService>(PrismaService);
  });

  afterEach(async () => {
    jest.restoreAllMocks();
    await cleanupDatabase(prisma);
  });

  afterAll(async () => {
    await app.close();
  });

  // ============================================================
  // helpers
  // ============================================================

  function suffix() {
    return `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
  }

  async function login(username: string, password: string): Promise<string> {
    const resp = await request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username, password })
      .expect(200);
    return resp.body.data.accessToken as string;
  }

  async function ensureRole(code: 'Administrator' | 'Employee' | 'MeetingManager' | 'Leader') {
    return prisma.role.upsert({
      where: { code },
      create: { code, name: code, enabled: true, isBuiltIn: true },
      update: { enabled: true },
    });
  }

  async function setupAdmin() {
    const s = suffix();
    const adminUser = await createAdminUser({
      username: `t_ma_adm_${s}`,
      email: `t_ma_adm_${s}@example.com`,
      password: 'Admin@123',
      displayName: `MA Admin ${s}`,
    });
    const adminToken = await login(adminUser.username, 'Admin@123');
    return { adminUser, adminToken };
  }

  async function setupEmployee() {
    const s = suffix();
    const employee = await createTestUser({
      username: `t_ma_emp_${s}`,
      email: `t_ma_emp_${s}@example.com`,
      password: 'Emp@123',
      displayName: `MA Emp ${s}`,
    });
    const role = await ensureRole('Employee');
    await assignRoleToUser(employee.id, role.id);
    const empToken = await login(employee.username, 'Emp@123');
    return { employee, empToken };
  }

  async function setupManager() {
    const s = suffix();
    const managerUser = await createTestUser({
      username: `t_ma_mgr_${s}`,
      email: `t_ma_mgr_${s}@example.com`,
      password: 'Mgr@123',
      displayName: `MA Mgr ${s}`,
    });
    const role = await ensureRole('MeetingManager');
    await assignRoleToUser(managerUser.id, role.id);
    const mgrToken = await login(managerUser.username, 'Mgr@123');
    return { managerUser, mgrToken };
  }

  // 创建一个没有任何会议角色的普通系统用户（非 Employee/Administrator/MeetingManager/Leader）
  async function setupNoRoleUser() {
    const s = suffix();
    const user = await createTestUser({
      username: `t_ma_nor_${s}`,
      email: `t_ma_nor_${s}@example.com`,
      password: 'Nor@123',
      displayName: `MA NoRole ${s}`,
    });
    const noRoleToken = await login(user.username, 'Nor@123');
    return { user, noRoleToken };
  }

  // ============================================================
  // GET /meeting-attendance/users
  // ============================================================

  describe('GET /meeting-attendance/users', () => {
    it('[1] admin 获取用户列表 → 200 + 分页结构', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('users');
      expect(resp.body).toHaveProperty('pagination');
      expect(Array.isArray(resp.body.users)).toBe(true);
      expect(resp.body.pagination).toHaveProperty('page');
      expect(resp.body.pagination).toHaveProperty('total');
    });

    it('[2] manager 获取用户列表 → 200', async () => {
      const { mgrToken } = await setupManager();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${mgrToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('users');
    });

    it('[3] 支持分页参数 page/limit → 200 + pagination 正确', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users?page=1&limit=5')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body.pagination.page).toBe(1);
      expect(resp.body.pagination.limit).toBe(5);
    });

    it('[4] 无 Authorization → 401', async () => {
      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users')
        .expect(401);
    });

    it('[5] 普通员工（非 admin/manager）→ 403', async () => {
      const { empToken } = await setupEmployee();

      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${empToken}`)
        .expect(403);
    });
  });

  // ============================================================
  // POST /meeting-attendance/users
  // ============================================================

  describe('POST /meeting-attendance/users', () => {
    it('[6] admin 按 email 指派 Employee 角色 → 201 + 返回 user + message', async () => {
      const { adminToken } = await setupAdmin();
      const s = suffix();
      const target = await createTestUser({
        username: `t_ma_tgt_${s}`,
        email: `t_ma_tgt_${s}@example.com`,
        password: 'Tgt@123',
        displayName: `MA Target ${s}`,
      });

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ email: target.email, role: 'Employee' })
        .expect(201);

      expect(resp.body).toHaveProperty('user');
      expect(resp.body.user.email).toBe(target.email);
      expect(resp.body.user.role).toBe('Employee');
      expect(resp.body).toHaveProperty('message');
    });

    it('[7] admin 按 userId 指派 MeetingManager 角色 → 201', async () => {
      const { adminToken } = await setupAdmin();
      const s = suffix();
      const target = await createTestUser({
        username: `t_ma_tgt2_${s}`,
        email: `t_ma_tgt2_${s}@example.com`,
        password: 'Tgt@123',
      });

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ userId: target.id, role: 'MeetingManager' })
        .expect(201);

      expect(resp.body.user.role).toBe('MeetingManager');
    });

    it('[8] 既没有 email 也没有 userId → 400 Email or userId is required', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ role: 'Employee' })
        .expect(400);

      expect(resp.body.error).toMatch(/email or userId is required/i);
    });

    it('[9] email 对应用户不存在 → 404 User does not exist', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ email: 'nonexistent@nowhere.example', role: 'Employee' })
        .expect(404);

      expect(resp.body.error).toMatch(/user does not exist/i);
    });

    it('[10] 无 Authorization → 401', async () => {
      await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .send({ email: 'x@x.com', role: 'Employee' })
        .expect(401);
    });

    it('[11] 普通员工尝试创建 → 403', async () => {
      const { empToken } = await setupEmployee();

      await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users')
        .set('Authorization', `Bearer ${empToken}`)
        .send({ email: 'x@x.com', role: 'Employee' })
        .expect(403);
    });
  });

  // ============================================================
  // GET /meeting-attendance/users/search
  // ============================================================

  describe('GET /meeting-attendance/users/search', () => {
    it('[12] Employee 搜索 → 200 + { users: [...] }', async () => {
      const { empToken } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/search?q=test')
        .set('Authorization', `Bearer ${empToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('users');
      expect(Array.isArray(resp.body.users)).toBe(true);
    });

    it('[13] admin 搜索 → 200', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/search?q=admin')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('users');
    });

    it('[14] 搜索 q 为空字符串 → 200（返回全部，受 limit 截断）', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/search?q=&limit=5')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('users');
    });

    it('[15] 无 Authorization → 401', async () => {
      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/search?q=test')
        .expect(401);
    });

    it('[16] 没有任何会议角色的用户 → 403', async () => {
      const { noRoleToken } = await setupNoRoleUser();

      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/search?q=test')
        .set('Authorization', `Bearer ${noRoleToken}`)
        .expect(403);
    });
  });

  // ============================================================
  // GET /meeting-attendance/users/import  (下载 CSV 模板)
  // ============================================================

  describe('GET /meeting-attendance/users/import', () => {
    it('[17] admin 下载模板 → 200 + Content-Type: text/csv + 含 header 行', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.headers['content-type']).toMatch(/text\/csv/i);
      expect(resp.headers['content-disposition']).toMatch(/attachment/i);
      expect(resp.text).toContain('email');
      expect(resp.text).toContain('role');
    });

    it('[18] manager 下载模板 → 200', async () => {
      const { mgrToken } = await setupManager();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${mgrToken}`)
        .expect(200);

      expect(resp.headers['content-type']).toMatch(/text\/csv/i);
    });

    it('[19] 无 Authorization → 401', async () => {
      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/import')
        .expect(401);
    });

    it('[20] 普通员工 → 403', async () => {
      const { empToken } = await setupEmployee();

      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${empToken}`)
        .expect(403);
    });
  });

  // ============================================================
  // POST /meeting-attendance/users/import  (批量导入)
  // ============================================================

  describe('POST /meeting-attendance/users/import', () => {
    it('[21] 批量导入 1 个有效用户 → 200 + success=1, failed=0', async () => {
      const { adminToken } = await setupAdmin();
      const s = suffix();
      const target = await createTestUser({
        username: `t_ma_imp_${s}`,
        email: `t_ma_imp_${s}@example.com`,
        password: 'Imp@123',
      });

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ users: [{ email: target.email, role: 'Employee' }] })
        .expect(200);

      expect(resp.body.results.success).toBe(1);
      expect(resp.body.results.failed).toBe(0);
      expect(resp.body).toHaveProperty('message');
    });

    it('[22] 部分用户不存在 → 200 + 部分 success + failed + errors 含行号', async () => {
      const { adminToken } = await setupAdmin();
      const s = suffix();
      const existingUser = await createTestUser({
        username: `t_ma_imp2_${s}`,
        email: `t_ma_imp2_${s}@example.com`,
        password: 'Imp@123',
      });

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          users: [
            { email: existingUser.email, role: 'Employee' },
            { email: `ghost_${s}@nowhere.example`, role: 'Employee' },
          ],
        })
        .expect(200);

      expect(resp.body.results.success).toBe(1);
      expect(resp.body.results.failed).toBe(1);
      expect(resp.body.results.errors.length).toBeGreaterThan(0);
    });

    it('[23] users 数组为空 → 400 User data cannot be empty', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ users: [] })
        .expect(400);

      expect(resp.body.error).toMatch(/user data cannot be empty/i);
    });

    it('[24] 不传 users 字段 → 400', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({})
        .expect(400);

      expect(resp.body.error).toMatch(/user data cannot be empty/i);
    });

    it('[25] 无 Authorization → 401', async () => {
      await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .send({ users: [{ email: 'x@x.com', role: 'Employee' }] })
        .expect(401);
    });

    it('[26] 普通员工 → 403', async () => {
      const { empToken } = await setupEmployee();

      await request(app.getHttpServer())
        .post('/api/v1/meeting-attendance/users/import')
        .set('Authorization', `Bearer ${empToken}`)
        .send({ users: [{ email: 'x@x.com', role: 'Employee' }] })
        .expect(403);
    });
  });

  // ============================================================
  // GET /meeting-attendance/users/:id
  // ============================================================

  describe('GET /meeting-attendance/users/:id', () => {
    it('[27] admin 获取任意用户详情 → 200 + 含 id/email/role', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .get(`/api/v1/meeting-attendance/users/${employee.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body.id).toBe(employee.id);
      expect(resp.body).toHaveProperty('email');
      expect(resp.body).toHaveProperty('role');
    });

    it('[28] 用户获取自己的详情（自读权限）→ 200', async () => {
      const { employee, empToken } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .get(`/api/v1/meeting-attendance/users/${employee.id}`)
        .set('Authorization', `Bearer ${empToken}`)
        .expect(200);

      expect(resp.body.id).toBe(employee.id);
    });

    it('[29] 普通员工读取他人 → 403 Insufficient permissions', async () => {
      const { empToken } = await setupEmployee();
      const { employee: other } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .get(`/api/v1/meeting-attendance/users/${other.id}`)
        .set('Authorization', `Bearer ${empToken}`)
        .expect(403);

      expect(resp.body.error).toMatch(/insufficient permissions/i);
    });

    it('[30] ID 格式非法 → 400 Invalid id format', async () => {
      // 非法 UUID 触发 Prisma P2023，由 controller helper 统一兜底返 400。
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/not-a-valid-uuid')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(resp.body.error).toMatch(/invalid id format/i);
    });

    it('[30b] 合法 UUID 但用户不存在 → 404', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/users/00000000-0000-0000-0000-000000000000')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

      expect(resp.body.error).toMatch(/user does not exist/i);
    });

    it('[31] 无 Authorization → 401', async () => {
      const { employee } = await setupEmployee();

      await request(app.getHttpServer())
        .get(`/api/v1/meeting-attendance/users/${employee.id}`)
        .expect(401);
    });
  });

  // ============================================================
  // PUT /meeting-attendance/users/:id
  // ============================================================

  describe('PUT /meeting-attendance/users/:id', () => {
    it('[32] admin 更新用户为 MeetingManager 角色 → 200 + message', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .put(`/api/v1/meeting-attendance/users/${employee.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ role: 'MeetingManager' })
        .expect(200);

      expect(resp.body).toHaveProperty('message');
    });

    it('[33] 非法 role 值 → 400 Invalid role', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .put(`/api/v1/meeting-attendance/users/${employee.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ role: 'INVALID_ROLE_FOO' })
        .expect(400);

      expect(resp.body.error).toMatch(/invalid role/i);
    });

    it('[34] ID 格式非法 → 400 Invalid id format', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .put('/api/v1/meeting-attendance/users/not-a-valid-uuid')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ role: 'Employee' })
        .expect(400);

      expect(resp.body.error).toMatch(/invalid id format/i);
    });

    it('[34b] 合法 UUID 但目标用户不存在 → 404', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .put('/api/v1/meeting-attendance/users/00000000-0000-0000-0000-000000000000')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ role: 'Employee' })
        .expect(404);

      expect(resp.body.error).toMatch(/user does not exist/i);
    });

    it('[35] 普通员工尝试更新他人角色 → 403', async () => {
      const { empToken } = await setupEmployee();
      const { employee: other } = await setupEmployee();

      await request(app.getHttpServer())
        .put(`/api/v1/meeting-attendance/users/${other.id}`)
        .set('Authorization', `Bearer ${empToken}`)
        .send({ role: 'Employee' })
        .expect(403);
    });

    it('[36] 无 Authorization → 401', async () => {
      const { employee } = await setupEmployee();

      await request(app.getHttpServer())
        .put(`/api/v1/meeting-attendance/users/${employee.id}`)
        .send({ role: 'Employee' })
        .expect(401);
    });
  });

  // ============================================================
  // DELETE /meeting-attendance/users/:id  (禁用 / 移除会议角色)
  // ============================================================

  describe('DELETE /meeting-attendance/users/:id', () => {
    it('[37] admin 禁用另一个用户 → 200 + message', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${employee.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('message');
    });

    it('[38] admin 禁用自己 → 400 You cannot remove your own access', async () => {
      const { adminUser, adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${adminUser.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(resp.body.error).toMatch(/cannot remove your own access/i);
    });

    it('[39] ID 格式非法 → 400 Invalid id format', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .delete('/api/v1/meeting-attendance/users/not-a-valid-uuid')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(resp.body.error).toMatch(/invalid id format/i);
    });

    it('[39b] 合法 UUID 但目标用户不存在 → 404', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .delete('/api/v1/meeting-attendance/users/00000000-0000-0000-0000-000000000000')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

      expect(resp.body.error).toMatch(/user does not exist/i);
    });

    it('[40] 普通员工 → 403', async () => {
      const { empToken } = await setupEmployee();
      const { employee: other } = await setupEmployee();

      await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${other.id}`)
        .set('Authorization', `Bearer ${empToken}`)
        .expect(403);
    });

    it('[41] 无 Authorization → 401', async () => {
      const { employee } = await setupEmployee();

      await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${employee.id}`)
        .expect(401);
    });
  });

  // ============================================================
  // POST /meeting-attendance/users/:id/reset-password
  // ============================================================

  describe('POST /meeting-attendance/users/:id/reset-password', () => {
    it('[42] 任何有效 token 请求 → 400 请从组织模块重置密码', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .post(`/api/v1/meeting-attendance/users/${employee.id}/reset-password`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({})
        .expect(400);

      expect(resp.body.error).toMatch(/please reset passwords from the organization module/i);
    });

    it('[43] 普通员工调用 → 400（service 层固定抛错，鉴权在 requireMeetingUser 所以 Employee 过鉴权，到 service 报 400）', async () => {
      const { empToken } = await setupEmployee();
      const { employee: other } = await setupEmployee();

      // controller 用 requireMeetingUser（非 requireAdminOrManager），Employee 可过鉴权
      // 进入 service 后直接 throw 400
      const resp = await request(app.getHttpServer())
        .post(`/api/v1/meeting-attendance/users/${other.id}/reset-password`)
        .set('Authorization', `Bearer ${empToken}`)
        .send({})
        .expect(400);

      expect(resp.body.error).toMatch(/please reset passwords from the organization module/i);
    });

    it('[44] 无 Authorization → 401', async () => {
      const { employee } = await setupEmployee();

      await request(app.getHttpServer())
        .post(`/api/v1/meeting-attendance/users/${employee.id}/reset-password`)
        .send({})
        .expect(401);
    });
  });

  // ============================================================
  // DELETE /meeting-attendance/users/:id/permanent
  // ============================================================

  describe('DELETE /meeting-attendance/users/:id/permanent', () => {
    it('[45] admin 永久删除另一个用户的会议角色 → 200 + message', async () => {
      const { adminToken } = await setupAdmin();
      const { employee } = await setupEmployee();

      const resp = await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${employee.id}/permanent`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('message');
    });

    it('[46] admin 永久删除自己 → 400 You cannot remove your own access', async () => {
      const { adminUser, adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${adminUser.id}/permanent`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(resp.body.error).toMatch(/cannot remove your own access/i);
    });

    it('[47] 普通员工调用 → 403（requireMeetingUser 过鉴权，service 层 isMeetingAdminRole 拒绝）', async () => {
      const { empToken } = await setupEmployee();
      const { employee: other } = await setupEmployee();

      await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${other.id}/permanent`)
        .set('Authorization', `Bearer ${empToken}`)
        .expect(403);
    });

    it('[48] 无 Authorization → 401', async () => {
      const { employee } = await setupEmployee();

      await request(app.getHttpServer())
        .delete(`/api/v1/meeting-attendance/users/${employee.id}/permanent`)
        .expect(401);
    });
  });
});
