/**
 * Roles API Integration Tests
 * 
 * 基于 HTTP API 的真正集成测试
 * 
 * 测试内容：
 * - 系统角色 CRUD 操作
 * - 权限分配
 * - 用户角色查询
 * - 内置角色保护
 * - v2.1 组织级角色分配
 * 
 * 基于文档: docs/modules/organization/07-api.md (Section 6: 系统角色管理)
 * 
 * @version v2.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 { createTestApp } from '../../helpers/app.helper';
import { setupIntegrationTest } from '../../helpers/test-setup.helper';

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

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

  beforeEach(async () => {
    // 🎯 使用统一的测试设置 helper（自动清理、创建管理员、登录）
    const context = await setupIntegrationTest(app, prisma);
    adminToken = context.adminToken;
    
    // 获取测试组织 ID（createAdminUser 创建的）
    const testOrg = await prisma.organization.findUnique({
      where: { code: 'TEST_ADMIN_ORG' },
    });
    testOrgId = testOrg!.id;
  });

  afterAll(async () => {
    // 最终清理和关闭应用
    await cleanupDatabase(prisma);
    await app.close();
  });

  /**
   * 🔧 辅助函数：创建测试角色
   * 简化重复的角色创建逻辑
   */
  async function createTestRole(roleData: {
    name: string;
    code?: string;
    description?: string;
  }) {
    const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
    const code = roleData.code || `ROLE_${uniqueId}`;

    const response = await request(app.getHttpServer())
      .post('/api/v1/roles')
      .set('Authorization', `Bearer ${adminToken}`)
      .send({
        code,
        name: `${roleData.name}_${uniqueId}`, // 名字也要唯一
        description: roleData.description,
      })
      .expect(201);

    return {
      roleId: response.body.data.id,
      code,
      name: response.body.data.name,
      roleData: response.body.data,
    };
  }

  describe('GET /api/v1/roles - 查询角色列表', () => {
    beforeEach(async () => {
      // 🎯 并行创建测试角色
      await Promise.all([
        createTestRole({ name: '部门经理' }),
        createTestRole({ name: 'HR员工' }),
      ]);
    });

    it('[API-ROLE-001] 应该返回角色列表', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(Array.isArray(response.body.data)).toBe(true);
      expect(response.body.data.length).toBeGreaterThan(0);
      expect(response.body.data[0]).toHaveProperty('id');
      expect(response.body.data[0]).toHaveProperty('code');
      expect(response.body.data[0]).toHaveProperty('name');
      expect(response.body.data[0]).toHaveProperty('userCount');
      expect(response.body.data[0]).toHaveProperty('permissionCount');
    });

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

      expect(response.body.success).toBe(true);
      expect(response.body.data.length).toBeGreaterThan(0);
      expect(response.body.data[0].name).toContain('部门经理');
    });
  });

  describe('POST /api/v1/roles - 创建角色', () => {
    it('[API-ROLE-003] 应该成功创建角色', async () => {
      const { roleId, code, roleData } = await createTestRole({
        name: '部门经理',
        description: '部门管理角色',
      });

      expect(roleData).toHaveProperty('id');
      expect(roleData.code).toBe(code);
      expect(roleData.isBuiltIn).toBe(false);

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

      expect(role).toBeDefined();
      expect(role!.code).toBe(code);
    });

    it('[API-ROLE-004] 角色代码重复应返回409', async () => {
      // 先创建一个角色
      const { code } = await createTestRole({ name: '部门经理' });

      // 尝试创建相同代码的角色
      const response = await request(app.getHttpServer())
        .post('/api/v1/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code, // 相同代码
          name: '部门经理2', // 不同名字
        })
        .expect(409);

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

    it('[API-ROLE-005] 缺少必填字段应返回400', async () => {
      const response = await request(app.getHttpServer())
        .post('/api/v1/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          // 缺少 code 和 name
          description: 'Test role',
        })
        .expect(400);

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

  describe('GET /api/v1/roles/:id - 查询角色详情', () => {
    let roleId: string;

    beforeEach(async () => {
      // 🎯 使用辅助函数创建测试角色
      const role = await createTestRole({ name: '部门经理' });
      roleId = role.roleId;
    });

    it('[API-ROLE-006] 应该返回角色详情', async () => {
      const response = await request(app.getHttpServer())
        .get(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id', roleId);
      expect(response.body.data).toHaveProperty('code');
      expect(response.body.data).toHaveProperty('name');
    });

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

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

  describe('PUT /api/v1/roles/:id - 更新角色', () => {
    let roleId: string;

    beforeEach(async () => {
      // 🎯 使用辅助函数创建测试角色
      const role = await createTestRole({ name: '部门经理' });
      roleId = role.roleId;
    });

    it('[API-ROLE-008] 应该成功更新角色信息', async () => {
      const uniqueSuffix = Date.now() + Math.random();
      const updateDto = {
        name: `高级部门经理_${uniqueSuffix}`,
        description: '高级部门管理角色',
      };

      const response = await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send(updateDto);

      expect(response.status).toBe(200);
      expect(response.body.success).toBe(true);
      expect(response.body.data.name).toBe(`高级部门经理_${uniqueSuffix}`);
      expect(response.body.data.description).toBe('高级部门管理角色');

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

      expect(role!.name).toBe(`高级部门经理_${uniqueSuffix}`);
    });

    it('[API-ROLE-009] 不能修改角色代码', async () => {
      const uniqueSuffix = Date.now() + Math.random();
      // 尝试修改代码（会被忽略或返回错误）
      const response = await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'NEW_CODE', // 尝试修改代码
          name: `修改后的名字_${uniqueSuffix}`,
        })
        .expect(200);

      expect(response.body.success).toBe(true);
      
      // 验证代码没有被修改
      const role = await prisma.role.findUnique({
        where: { id: roleId },
      });
      
      expect(role!.code).not.toBe('NEW_CODE'); // 代码保持原值
      expect(role!.name).toBe(`修改后的名字_${uniqueSuffix}`); // 名字已修改
    });
  });

  describe('DELETE /api/v1/roles/:id - 删除角色', () => {
    let roleId: string;

    beforeEach(async () => {
      // 🎯 使用辅助函数创建测试角色
      const role = await createTestRole({ name: '部门经理' });
      roleId = role.roleId;
    });

    it('[API-ROLE-010] 应该成功删除角色', async () => {
      await request(app.getHttpServer())
        .delete(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      // 验证已删除
      const role = await prisma.role.findUnique({
        where: { id: roleId },
      });

      expect(role).toBeNull();
    });

    it('[API-ROLE-011] 不能删除内置角色', async () => {
      // 创建内置角色
      const uniqueId = Date.now() + Math.random();
      const builtInRole = await prisma.role.create({
        data: {
          code: `BUILTIN_${uniqueId}`,
          name: `内置角色_${uniqueId}`,
          isBuiltIn: true,
        },
      });

      const response = await request(app.getHttpServer())
        .delete(`/api/v1/roles/${builtInRole.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(403);

      expect(response.body.success).toBe(false);
      expect(JSON.stringify(response.body.error)).toContain('SYSTEM_ROLE_PROTECTED');
    });

    it('[API-ROLE-012] 有用户时不能删除角色', async () => {
      // 创建用户
      const uniqueUsername = `testuser_${Date.now()}_${Math.random().toString(36).substring(7)}`;
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: uniqueUsername,
          email: `${uniqueUsername}@example.com`,
          password: 'Test@123',
          displayName: 'Test User',
        });

      if (userResponse.status !== 201) {
        console.error('创建用户失败:', JSON.stringify(userResponse.body, null, 2));
      }

      expect(userResponse.status).toBe(201);

      // 分配角色
      const assignResponse = await request(app.getHttpServer())
        .post(`/api/v1/users/${userResponse.body.data.id}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          assignments: [
            {
              roleId,
              organizationId: testOrgId,
            },
          ],
        });

      expect([200, 201]).toContain(assignResponse.status); // 可能是200或201

      // 尝试删除
      const response = await request(app.getHttpServer())
        .delete(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`);

      expect(response.status).toBe(400);
      expect(response.body.success).toBe(false);
      expect(JSON.stringify(response.body.error)).toContain('ROLE_HAS_USERS');
    });
  });

  describe('PUT /api/v1/roles/:id/permissions - 分配权限', () => {
    let roleId: string;
    let permissionIds: string[];

    beforeEach(async () => {
      // 🎯 使用辅助函数创建角色
      const role = await createTestRole({ name: '部门经理' });
      roleId = role.roleId;

      // 创建或获取权限（使用 upsert 避免唯一约束冲突）
      const perm1 = await prisma.permission.upsert({
        where: {
          resource_action: {
            resource: 'user',
            action: 'read',
          },
        },
        create: {
          resource: 'user',
          action: 'read',
          description: '查看用户',
          module: 'organization',
        },
        update: {},
      });

      const perm2 = await prisma.permission.upsert({
        where: {
          resource_action: {
            resource: 'user',
            action: 'write',
          },
        },
        create: {
          resource: 'user',
          action: 'write',
          description: '编辑用户',
          module: 'organization',
        },
        update: {},
      });

      permissionIds = [perm1.id, perm2.id];
    });

    it('[API-ROLE-013] 应该成功分配权限', async () => {
      const response = await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds,
        })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('permissionCount', 2);

      // 验证数据库
      const rolePermissions = await prisma.rolePermission.findMany({
        where: { roleId },
      });

      expect(rolePermissions).toHaveLength(2);
    });

    it('[API-ROLE-014] 传入空数组应清空所有权限', async () => {
      // 先分配权限
      await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds,
        });

      // 清空权限
      const response = await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds: [],
        })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.permissionCount).toBe(0);

      // 验证数据库
      const rolePermissions = await prisma.rolePermission.findMany({
        where: { roleId },
      });

      expect(rolePermissions).toHaveLength(0);
    });

    it('[API-ROLE-015] 权限ID不存在应返回404', async () => {
      const response = await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds: ['00000000-0000-0000-0000-000000000000'], // 有效的UUID但不存在
        });

      expect([400, 404]).toContain(response.status); // 可能是400（无效UUID）或404（不存在）
      expect(response.body.success).toBe(false);
    });
  });

  describe('GET /api/v1/roles/:id/permissions - 查询角色权限', () => {
    let roleId: string;

    beforeEach(async () => {
      // 🎯 使用辅助函数创建角色
      const role = await createTestRole({ name: '部门经理' });
      roleId = role.roleId;

      // 创建并分配权限（使用 upsert 避免唯一约束冲突）
      const perm = await prisma.permission.upsert({
        where: {
          resource_action: {
            resource: 'user',
            action: 'read',
          },
        },
        create: {
          resource: 'user',
          action: 'read',
          description: '查看用户',
          module: 'organization',
        },
        update: {},
      });

      await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds: [perm.id],
        });
    });

    it('[API-ROLE-016] 应该返回角色的所有权限', async () => {
      const response = await request(app.getHttpServer())
        .get(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(Array.isArray(response.body.data)).toBe(true);
      expect(response.body.data.length).toBe(1);
      expect(response.body.data[0]).toHaveProperty('resource', 'user');
      expect(response.body.data[0]).toHaveProperty('action', 'read');
    });
  });

  describe('完整业务流程测试', () => {
    it('[API-ROLE-FLOW-001] 应该完成完整的角色创建和权限分配流程', async () => {
      // 1. 🎯 使用辅助函数创建角色
      const { roleId } = await createTestRole({
        name: '部门经理',
        description: '部门管理角色',
      });

      // 2. 创建或获取权限（使用 upsert 避免唯一约束冲突）
      const perm1 = await prisma.permission.upsert({
        where: {
          resource_action: {
            resource: 'user',
            action: 'read',
          },
        },
        create: {
          resource: 'user',
          action: 'read',
          description: '查看用户',
          module: 'organization',
        },
        update: {},
      });

      const perm2 = await prisma.permission.upsert({
        where: {
          resource_action: {
            resource: 'user',
            action: 'write',
          },
        },
        create: {
          resource: 'user',
          action: 'write',
          description: '编辑用户',
          module: 'organization',
        },
        update: {},
      });

      // 3. 分配权限
      await request(app.getHttpServer())
        .put(`/api/v1/roles/${roleId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          permissionIds: [perm1.id, perm2.id],
        })
        .expect(200);

      // 4. 创建用户
      const uniqueUsername = `manager_${Date.now()}_${Math.random().toString(36).substring(7)}`;
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: uniqueUsername,
          email: `${uniqueUsername}@example.com`,
          password: 'Test@123',
          displayName: 'Manager',
        });

      const userId = userResponse.body.data.id;

      // 5. 分配角色给用户
      const assignResponse = await request(app.getHttpServer())
        .post(`/api/v1/users/${userId}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          assignments: [
            {
              roleId,
              organizationId: testOrgId, // 组织级角色
            },
          ],
        });

      expect([200, 201]).toContain(assignResponse.status);

      // 6. 查询用户权限
      const permissionsResponse = await request(app.getHttpServer())
        .get(`/api/v1/users/${userId}/permissions`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(permissionsResponse.body.data.permissions).toHaveLength(2);

      // 7. 查询角色详情
      const roleDetailResponse = await request(app.getHttpServer())
        .get(`/api/v1/roles/${roleId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(roleDetailResponse.body.data.id).toBe(roleId);

      console.log('✅ 角色创建和权限分配完整流程测试通过');
    });
  });
});

