/**
 * Departments API Integration Tests
 * 
 * 基于 HTTP API 的真正集成测试
 * 
 * 测试内容：
 * - 部门 CRUD 操作
 * - 部门树形结构
 * - 部门负责人管理
 * - 部门成员管理
 * - v2.1.17 根部门约束
 * 
 * 基于文档: docs/modules/organization/07-api.md (Section 3: 部门管理)
 * 
 * @version v2.1.2 (优化版 - 使用 test-setup.helper)
 */

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

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

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

  beforeEach(async () => {
    // 🎯 使用统一的测试设置 helper（自动清理、创建管理员、登录、创建组织）
    const context = await setupIntegrationTestWithOrganization(app, prisma, {
      createOrganization: true,
      organizationName: 'Test Organization',
    });
    
    adminToken = context.adminToken;
    organizationId = context.organizationId!;
    rootDepartmentId = context.rootDepartmentId!;
  });

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

  describe('GET /api/v1/departments/tree - 部门树形结构', () => {
    beforeEach(async () => {
      // 创建部门层级
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        });
      
      if (createResponse.status !== 201) {
        console.error('Failed to create department:', createResponse.status, createResponse.body);
      }
    });

    it('[API-DEPT-001] 应该返回部门树形结构', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/departments/tree')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ organizationId })
        .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('children');
      expect(response.body.data[0]).toHaveProperty('employeeCount');
    });
  });

  describe('POST /api/v1/departments - 创建部门', () => {
    it('[API-DEPT-002] 应该成功创建子部门', async () => {
      const createDto = {
        code: 'TECH',
        name: '技术部',
        organizationId,
        parentId: rootDepartmentId,
        description: '技术研发部门',
      };

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

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id');
      expect(response.body.data.code).toBe('TECH');
      expect(response.body.data.name).toBe('技术部');
      expect(response.body.data.parentId).toBe(rootDepartmentId);

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

      expect(dept).toBeDefined();
      expect(dept!.parentId).toBe(rootDepartmentId);
    });

    it('[API-DEPT-003] 不能手动创建顶级部门 (v2.1.17 ⭐)', async () => {
      const response = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'ROOT',
          name: 'Root Department',
          organizationId,
          parentId: null, // 尝试创建顶级部门
        })
        .expect(400);

      expect(response.body.success).toBe(false);
      expect(response.body.error.message).toContain('top-level department');
    });

    it('[API-DEPT-004] 部门代码重复应返回409', async () => {
      // 先创建一个部门
      await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        })
        .expect(201);

      // 尝试创建相同代码的部门
      const response = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH', // 相同代码
          name: '技术部2',
          organizationId,
          parentId: rootDepartmentId,
        })
        .expect(409);

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

    it('[API-DEPT-005] 父部门不存在应返回404', async () => {
      const response = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: '00000000-0000-0000-0000-000000000000', // 有效UUID但不存在
        })
        .expect(404);

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

  describe('GET /api/v1/departments/:id - 查询部门详情', () => {
    let departmentId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        });

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

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

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id', departmentId);
      expect(response.body.data).toHaveProperty('code', 'TECH');
      expect(response.body.data).toHaveProperty('name', '技术部');
      expect(response.body.data).toHaveProperty('employeeCount');
    });

    it('[API-DEPT-007] 部门不存在应返回404', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/departments/00000000-0000-0000-0000-000000000000') // 有效UUID但不存在
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

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

  describe('PATCH /api/v1/departments/:id - 更新部门', () => {
    let departmentId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        });

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

    it('[API-DEPT-008] 应该成功更新部门信息', async () => {
      const updateDto = {
        name: '技术研发部',
        description: '负责技术研发工作',
      };

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

      expect(response.body.success).toBe(true);
      expect(response.body.data.name).toBe('技术研发部');
      expect(response.body.data.description).toBe('负责技术研发工作');

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

      expect(dept!.name).toBe('技术研发部');
    });

    it('[API-DEPT-009] 不能修改部门代码', async () => {
      // 尝试修改code，但由于UpdateDepartmentDto不包含code字段
      // 全局ValidationPipe (whitelist: true)会自动忽略该字段
      // 因此请求会成功，但code不会被修改
      const originalDept = await prisma.department.findUnique({
        where: { id: departmentId },
      });

      const response = await request(app.getHttpServer())
        .put(`/api/v1/departments/${departmentId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'NEW_CODE', // 尝试修改代码（会被忽略）
          name: 'Updated Name', // 有效字段
        })
        .expect(200);

      // 验证code没有被修改，但name已更新
      expect(response.body.success).toBe(true);
      expect(response.body.data.code).toBe(originalDept!.code); // code未变
      expect(response.body.data.name).toBe('Updated Name'); // name已更新
    });
  });

  describe('DELETE /api/v1/departments/:id - 删除部门', () => {
    let departmentId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        });

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

    it('[API-DEPT-010] 应该成功删除空部门', async () => {
      await request(app.getHttpServer())
        .delete(`/api/v1/departments/${departmentId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

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

      expect(dept).toBeDefined();
      expect(dept!.deletedAt).not.toBeNull();
    });

    it('[API-DEPT-011] 不能删除根部门 (v2.1.17 ⭐)', async () => {
      const response = await request(app.getHttpServer())
        .delete(`/api/v1/departments/${rootDepartmentId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(response.body.success).toBe(false);
      expect(response.body.error.message).toContain('root department');
    });

    it('[API-DEPT-012] 有子部门时不能删除', async () => {
      // 创建子部门
      await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH_SUB',
          name: '技术子部门',
          organizationId,
          parentId: departmentId,
        });

      // 尝试删除父部门
      const response = await request(app.getHttpServer())
        .delete(`/api/v1/departments/${departmentId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(response.body.success).toBe(false);
      expect(response.body.error.message).toMatch(/子部门|children/);
    });
  });

  describe('PUT /api/v1/departments/:id/head - 设置部门负责人', () => {
    let departmentId: string;
    let userId: string;

    beforeEach(async () => {
      // 创建部门
      const deptResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        });

      departmentId = deptResponse.body.data.id;

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

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

    it('[API-DEPT-013] 应该成功设置部门负责人', async () => {
      const response = await request(app.getHttpServer())
        .put(`/api/v1/departments/${departmentId}/head`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          headId: userId,
        })
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.headId).toBe(userId);

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

      expect(dept!.headId).toBe(userId);
    });

    it('[API-DEPT-014] 用户不存在应返回404', async () => {
      const response = await request(app.getHttpServer())
        .put(`/api/v1/departments/${departmentId}/head`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          headId: '00000000-0000-0000-0000-000000000000', // 有效UUID但不存在
        })
        .expect(404);

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

  describe('完整业务流程测试', () => {
    it('[API-DEPT-FLOW-001] 应该完成完整的部门层级创建流程', async () => {
      // 1. 创建一级部门（技术部）
      const techDeptResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TECH',
          name: '技术部',
          organizationId,
          parentId: rootDepartmentId,
        })
        .expect(201);

      const techDeptId = techDeptResponse.body.data.id;

      // 2. 创建二级部门（前端组）
      const frontendResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'FRONTEND',
          name: '前端组',
          organizationId,
          parentId: techDeptId,
        })
        .expect(201);

      // 3. 创建二级部门（后端组）
      const backendResponse = await request(app.getHttpServer())
        .post('/api/v1/departments')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'BACKEND',
          name: '后端组',
          organizationId,
          parentId: techDeptId,
        })
        .expect(201);

      // 4. 查询部门树，验证层级结构
      const treeResponse = await request(app.getHttpServer())
        .get('/api/v1/departments/tree')
        .set('Authorization', `Bearer ${adminToken}`)
        .query({ organizationId })
        .expect(200);

      expect(treeResponse.body.data.length).toBeGreaterThan(0);

      // 5. 创建部门负责人
      const userResponse = await request(app.getHttpServer())
        .post('/api/v1/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          username: 'techhead',
          email: 'techhead@example.com',
          password: 'Test@123',
          displayName: 'Tech Head',
        });

      const userId = userResponse.body.data.id;

      // 6. 设置部门负责人
      await request(app.getHttpServer())
        .put(`/api/v1/departments/${techDeptId}/head`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          headId: userId,
        })
        .expect(200);

      // 7. 查询部门详情，验证负责人
      const detailResponse = await request(app.getHttpServer())
        .get(`/api/v1/departments/${techDeptId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(detailResponse.body.data.head).toBeDefined();
      expect(detailResponse.body.data.head.id).toBe(userId);

      console.log('✅ 部门层级创建完整流程测试通过');
    });
  });
});

