/**
 * Users API Integration Tests
 * 
 * 基于 HTTP API 的真正集成测试
 * 
 * 测试内容：
 * - 用户 CRUD 操作
 * - 角色分配
 * - 部门归属
 * - 状态管理
 * - 权限验证
 * 
 * 基于文档: docs/modules/organization/07-api.md (Section 3: 用户管理)
 * 
 * @version v2.1.1
 */

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

describe('Users API Integration Tests', () => {
  let app: INestApplication;
  let prisma: PrismaService;
  let adminToken: string;
  let organizationId: string;
  let departmentId: string;

  beforeAll(async () => {
    app = await createTestApp();
    prisma = app.get<PrismaService>(PrismaService);
  });

  beforeEach(async () => {
    await cleanupDatabase(prisma);

    const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;

    // 1. 创建测试组织
    const testOrg = await prisma.organization.create({
      data: {
        code: `t_${uniqueId}_ORG`,
        name: `t_${uniqueId}_Test Org`,
        status: 'ACTIVE',
      },
    });
    organizationId = testOrg.id;

    // 2. 创建根部门
    const rootDept = await prisma.department.create({
      data: {
        code: `t_${uniqueId}_ROOT`,
        name: 'Root Department',
        organizationId: testOrg.id,
      },
    });
    departmentId = rootDept.id;

    // 3. 创建临时管理员并登录（种子角色/权限由 seed 保留）
    const admin = await createTestUser({
      username: `t_${uniqueId}_admin`,
      email: `t_${uniqueId}_admin@test.com`,
      password: 'Admin@123',
      displayName: 'Admin User',
      status: 'ACTIVE',
      source: 'LOCAL',
    });

    // 分配 Administrator 角色（种子已创建）
    const adminRole = await prisma.role.findUnique({ where: { code: 'Administrator' } });
    if (adminRole) {
      await prisma.userRole.create({
        data: { userId: admin.id, roleId: adminRole.id, organizationId: testOrg.id },
      });
    }

    const loginResponse = await request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username: `t_${uniqueId}_admin`, password: 'Admin@123' });

    adminToken = loginResponse.body.data.accessToken;
  });

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

  describe('POST /api/v1/users - 创建用户', () => {
    it('[API-USER-001] 应该成功创建本地用户', async () => {
      const createDto = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'Test@123',
        displayName: 'Test User',
        employeeId: 'EMP001',
        phone: '13800138000',
        region: 'CN',
      };

      const response = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(createDto)
        .expect(201);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id');
      expect(response.body.data.username).toBe('testuser');
      expect(response.body.data.email).toBe('test@example.com');
      expect(response.body.data.source).toBe('LOCAL');
      expect(response.body.data).not.toHaveProperty('passwordHash'); // 密码不应返回

      // 验证数据库
      const user = await prisma.user.findUnique({
        where: { id: response.body.data.id },
      });

      expect(user).toBeDefined();
      expect(user!.passwordHash).toBeDefined(); // 数据库中有密码哈希
    });

    it('[API-USER-002] 用户名重复应返回409', async () => {
      // 先创建一个用户
      await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test1@example.com',
          password: 'Test@123',
          displayName: 'Test User 1',
        })
        .expect(201);

      // 尝试创建相同用户名
      const response = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser', // 相同用户名
          email: 'test2@example.com',
          password: 'Test@123',
          displayName: 'Test User 2',
        })
        .expect(409);

      expect(response.body.success).toBe(false);
      expect(response.body.error.code).toContain('USERNAME_EXISTS');
    });

    it('[API-USER-003] 邮箱重复应返回409', async () => {
      await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser1',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User 1',
        })
        .expect(201);

      const response = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser2',
          email: 'test@example.com', // 相同邮箱
          password: 'Test@123',
          displayName: 'Test User 2',
        })
        .expect(409);

      expect(response.body.success).toBe(false);
      expect(response.body.error.code).toContain('EMAIL_EXISTS');
    });

    it('[API-USER-004] 密码格式不符合要求应返回400', async () => {
      const response = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: '123', // 太短
          displayName: 'Test User',
        })
        .expect(400);

      expect(response.body.success).toBe(false);
    });
  });

  describe('GET /api/v1/users - 查询用户列表', () => {
    beforeEach(async () => {
      // 创建测试用户
      await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'user1',
          email: 'user1@example.com',
          password: 'Test@123',
          displayName: 'User 1',
        });

      await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'user2',
          email: 'user2@example.com',
          password: 'Test@123',
          displayName: 'User 2',
        });
    });

    it('[API-USER-005] 应该返回用户列表（分页）', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ page: 1, pageSize: 10 })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('items');
      expect(response.body.data).toHaveProperty('total');
      expect(Array.isArray(response.body.data.items)).toBe(true);
      expect(response.body.data.items.length).toBeGreaterThan(0);
    });

    it('[API-USER-006] 应该支持关键字搜索', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ keyword: 'user1' })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.items.length).toBeGreaterThan(0);
      expect(response.body.data.items[0].username).toContain('user1');
    });

    it('[API-USER-007] 应该支持状态过滤', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ status: 'ACTIVE' })
        .expect(200);

      expect(response.body.success).toBe(true);
      response.body.data.items.forEach((user: any) => {
        expect(user.status).toBe('ACTIVE');
      });
    });

    it('[API-USER-008] 应该支持 externalId 精确过滤（OpenClaw 同步脚本用）', async () => {
      // 直接在 DB 里 patch externalId，模拟 Entra 同步过的用户
      const aadGuid = '773ecaf4-f88c-444f-b14f-bb0b7fc5cabd';
      await prisma.user.updateMany({
        where: { username: 'user1' },
        data: { externalId: aadGuid, externalSource: 'ENTRA' },
      });

      const response = await request(app.getHttpServer())
        .get('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ externalId: aadGuid })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.items).toHaveLength(1);
      expect(response.body.data.items[0].username).toBe('user1');

      // 不存在的 externalId 应返回空
      const emptyRes = await request(app.getHttpServer())
        .get('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ externalId: '00000000-0000-0000-0000-000000000000' })
        .expect(200);
      expect(emptyRes.body.data.items).toHaveLength(0);
    });
  });

  describe('GET /api/v1/users/:id - 查询用户详情', () => {
    let userId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User',
        });

      userId = createResponse.body.data.id;
    });

    it('[API-USER-008] 应该返回用户详情', async () => {
      const response = await request(app.getHttpServer())
        .get(`/api/v1/users/${userId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id', userId);
      expect(response.body.data).toHaveProperty('username');
      expect(response.body.data).toHaveProperty('email');
      expect(response.body.data).not.toHaveProperty('passwordHash');
    });

    it('[API-USER-009] 用户不存在应返回404', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/users/00000000-0000-0000-0000-000000000000')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

      expect(response.body.success).toBe(false);
    });
  });

  describe('PATCH /api/v1/users/:id - 更新用户', () => {
    let userId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User',
        });

      userId = createResponse.body.data.id;
    });

    it('[API-USER-010] 应该成功更新用户信息', async () => {
      const updateDto = {
        displayName: 'Updated Name',
        phone: '13900139000',
      };

      const response = await request(app.getHttpServer())
        .patch(`/api/v1/users/${userId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send(updateDto)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.displayName).toBe('Updated Name');
      expect(response.body.data.phone).toBe('13900139000');

      // 验证数据库
      const user = await prisma.user.findUnique({
        where: { id: userId },
      });

      expect(user!.displayName).toBe('Updated Name');
    });

    it('[API-USER-011] 不能修改用户名', async () => {
      const response = await request(app.getHttpServer())
        .patch(`/api/v1/users/${userId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'newusername', // 尝试修改用户名
        });

      // 验证用户名没有被修改（username字段被DTO忽略）
      expect(response.status).toBe(200);
      
      const user = await prisma.user.findUnique({
        where: { id: userId },
      });
      expect(user!.username).toBe('testuser'); // 用户名保持不变
    });
  });

  describe('DELETE /api/v1/users/:id - 删除用户', () => {
    let userId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User',
        });

      userId = createResponse.body.data.id;
    });

    it('[API-USER-012] 应该成功软删除用户', async () => {
      await request(app.getHttpServer())
        .delete(`/api/v1/users/${userId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      // 验证软删除
      const user = await prisma.user.findFirst({
        where: { id: userId },
      });

      expect(user).toBeDefined();
      expect(user!.deletedAt).not.toBeNull();
      expect(user!.status).toBe('TERMINATED');
    });
  });

  describe('POST /api/v1/users/:id/roles - 分配角色', () => {
    let userId: string;
    let roleId: string;

    beforeEach(async () => {
      // 创建用户
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User',
        });

      userId = userResponse.body.data.id;

      // 创建角色（使用唯一代码和名字）
      const uniqueId = Date.now() + Math.random();
      const roleResponse = await request(app.getHttpServer())
        .post('/api/v1/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: `TEST_ROLE_${uniqueId}`,
          name: `Test Role ${uniqueId}`,
          description: 'Test role for API testing',
        });

      roleId = roleResponse.body.data.id;
    });

    it('[API-USER-013] 应该成功分配角色', async () => {
      const response = await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          assignments: [ // v2.1: 使用 assignments 字段
            {
              roleId,
              organizationId, // v2.1: 支持组织级角色分配
            },
          ],
        })
        .expect(200); // 文档规定：POST /users/:id/roles 返回 200

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('assignedRoles');
      expect(response.body.data.assignedRoles).toHaveLength(1);
      expect(response.body.data.assignedRoles[0].roleId).toBe(roleId);

      // 验证数据库
      const userRole = await prisma.userRole.findFirst({
        where: {
          userId,
          roleId,
        },
      });

      expect(userRole).toBeDefined();
      expect(userRole!.organizationId).toBe(organizationId);
    });

    it('[API-USER-014] 应该支持全局角色分配', async () => {
      const response = await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          assignments: [ // v2.1: 使用 assignments 字段
            {
              roleId,
              organizationId: null, // 全局角色
            },
          ],
        })
        .expect(200); // 文档规定：POST /users/:id/roles 返回 200

      expect(response.body.success).toBe(true);

      const userRole = await prisma.userRole.findFirst({
        where: {
          userId,
          roleId,
        },
      });

      expect(userRole!.organizationId).toBeNull();
    });
  });

  describe('POST /api/v1/users/:id/departments - 添加部门归属', () => {
    let userId: string;
    let positionId: string;

    beforeEach(async () => {
      // 创建用户
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'testuser',
          email: 'test@example.com',
          password: 'Test@123',
          displayName: 'Test User',
        });

      userId = userResponse.body.data.id;

      // 创建岗位
      const positionResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'ENG_L3',
          name: '工程师',
          level: 3,
        });

      positionId = positionResponse.body.data.id;
    });

    it('[API-USER-015] 应该成功添加用户到部门', async () => {
      const response = await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/departments`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          departmentId,
          positionId,
          isPrimary: true,
          joinedAt: new Date().toISOString(),
        })
        .expect(201); // 文档规定：POST /users/:id/departments 返回 201

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('userId', userId);
      expect(response.body.data).toHaveProperty('departmentId', departmentId);
      expect(response.body.data.isPrimary).toBe(true);

      // 验证数据库
      const userDept = await prisma.userDepartment.findFirst({
        where: {
          userId,
          departmentId,
        },
      });

      expect(userDept).toBeDefined();
      expect(userDept!.isPrimary).toBe(true);
    });
  });

  describe('完整业务流程测试', () => {
    it('[API-USER-FLOW-001] 应该完成完整的用户入职流程', async () => {
      // 1. 创建岗位
      const positionResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'ENG_L3',
          name: '工程师',
          level: 3,
        });

      const positionId = positionResponse.body.data.id;

      // 2. 创建角色（使用唯一代码和名字）
      const uniqueId = Date.now() + Math.random();
      const roleResponse = await request(app.getHttpServer())
        .post('/api/v1/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: `EMPLOYEE_${uniqueId}`,
          name: `员工 ${uniqueId}`,
        });

      const roleId = roleResponse.body.data.id;

      // 3. 创建用户
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'newemployee',
          email: 'newemployee@example.com',
          password: 'Test@123',
          displayName: 'New Employee',
          employeeId: 'EMP001',
        })
        .expect(201);

      const userId = userResponse.body.data.id;

      // 4. 分配部门
      await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/departments`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          departmentId,
          positionId,
          isPrimary: true,
          joinedAt: new Date().toISOString(),
        })
        .expect(201); // 文档规定：POST /users/:id/departments 返回 201

      // 5. 分配角色
      await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          assignments: [ // v2.1: 使用 assignments 字段
            {
              roleId,
              organizationId,
            },
          ],
        })
        .expect(200); // 文档规定：POST /users/:id/roles 返回 200

      // 6. 验证用户完整信息
      const detailResponse = await request(app.getHttpServer())
        .get(`/api/v1/users/${userId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(detailResponse.body.data.username).toBe('newemployee');
      expect(detailResponse.body.data.status).toBe('ACTIVE');

      console.log('✅ 用户入职完整流程测试通过');
    });
  });
});

