/**
 * Positions API Integration Tests
 * 
 * 基于 HTTP API 的真正集成测试
 * 
 * 测试内容：
 * - 岗位 CRUD 操作
 * - 岗位列表查询
 * - 岗位代码唯一性
 * - 岗位删除约束
 * 
 * 基于文档: 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 { createTestUser } from '../../helpers/factories';
import { createTestApp } from '../../helpers/app.helper';
import { setupIntegrationTestWithOrganization } from '../../helpers/test-setup.helper';

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

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

  beforeEach(async () => {
    // 🎯 使用统一的测试设置辅助函数
    const context = await setupIntegrationTestWithOrganization(app, prisma, {
      createOrganization: true,
    });
    
    adminToken = context.adminToken;
    organizationId = context.organizationId!;
  });

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

  describe('GET /api/v1/positions - 查询岗位列表', () => {
    beforeEach(async () => {
      // 创建测试岗位
      await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'P001',
          name: '软件工程师',
          level: 1,
        });

      await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'P002',
          name: '高级软件工程师',
          level: 2,
        });
    });

    it('[API-POSITION-001] 应该返回岗位列表', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/v1/positions')
        .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('level');
    });

    it('[API-POSITION-002] 应该支持按关键字搜索', async () => {
      // 创建带有唯一关键字的岗位，避免与种子数据冲突
      const uniqueKeyword = `独特搜索词${Date.now()}`;
      await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: `SEARCH_${Date.now()}`,
          name: `${uniqueKeyword}岗位`,
          level: 3,
        })
        .expect(201);

      const response = await request(app.getHttpServer())
        .get(`/api/v1/positions?keyword=${encodeURIComponent(uniqueKeyword)}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data.length).toBe(1);
      expect(response.body.data[0].name).toContain(uniqueKeyword);
    });
  });

  describe('POST /api/v1/positions - 创建岗位', () => {
    it('[API-POSITION-003] 应该成功创建岗位', async () => {
      const createDto = {
        code: 'MGR001',
        name: '技术经理',
        level: 3,
        description: '负责技术团队管理',
      };

      const response = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .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('MGR001');
      expect(response.body.data.name).toBe('技术经理');
      expect(response.body.data.level).toBe(3);

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

      expect(position).toBeDefined();
      expect(position!.code).toBe('MGR001');
    });

    it('[API-POSITION-004] 岗位代码重复应返回409', async () => {
      // 先创建一个岗位
      await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'DEV001',
          name: '开发工程师',
          level: 1,
        })
        .expect(201);

      // 尝试创建相同代码的岗位
      const response = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'DEV001', // 相同代码
          name: '开发工程师2',
          level: 1,
        })
        .expect(409);

      expect(response.body.success).toBe(false);
      expect(response.body.error).toBeDefined();
      // error 是一个对象，包含 error 字段
      expect(JSON.stringify(response.body.error)).toContain('CODE_EXISTS');
    });

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

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

  describe('GET /api/v1/positions/:id - 查询岗位详情', () => {
    let positionId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TEST001',
          name: '测试岗位',
          level: 1,
        });

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

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

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('id', positionId);
      expect(response.body.data).toHaveProperty('code', 'TEST001');
      expect(response.body.data).toHaveProperty('name', '测试岗位');
    });

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

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

  describe('PUT /api/v1/positions/:id - 更新岗位', () => {
    let positionId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'TEST002',
          name: '测试岗位',
          level: 1,
        });

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

    it('[API-POSITION-008] 应该成功更新岗位信息', async () => {
      const updateDto = {
        name: '高级测试岗位',
        level: 2,
        description: '新的描述',
      };

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

      expect(response.body.success).toBe(true);
      expect(response.body.data.name).toBe('高级测试岗位');
      expect(response.body.data.level).toBe(2);
      expect(response.body.data.description).toBe('新的描述');

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

      expect(position!.name).toBe('高级测试岗位');
      expect(position!.level).toBe(2);
    });

    it('[API-POSITION-009] 不能修改岗位代码', async () => {
      // 尝试修改代码（会被忽略，因为 DTO 中没有 code 字段）
      const response = await request(app.getHttpServer())
        .put(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'NEW_CODE', // 尝试修改代码
          name: '修改后的名字',
        })
        .expect(200);

      expect(response.body.success).toBe(true);
      
      // 验证代码没有被修改
      const position = await prisma.position.findUnique({
        where: { id: positionId },
      });
      
      expect(position!.code).toBe('TEST002'); // 代码保持不变
      expect(position!.name).toBe('修改后的名字'); // 名字已修改
    });
  });

  describe('DELETE /api/v1/positions/:id - 删除岗位', () => {
    let positionId: string;

    beforeEach(async () => {
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'DEL001',
          name: '待删除岗位',
          level: 1,
        });

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

    it('[API-POSITION-010] 应该成功删除岗位', async () => {
      await request(app.getHttpServer())
        .delete(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      // 验证已软删除（deletedAt 不为 null）
      const position = await prisma.position.findUnique({
        where: { id: positionId },
      });

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

    it('[API-POSITION-011] 有关联用户时不能删除', async () => {
      // 获取或创建根部门
      const rootDept = await prisma.department.upsert({
        where: { 
          organizationId_code: {
            organizationId,
            code: 'ROOT_POS_TEST',
          }
        },
        create: {
          code: 'ROOT_POS_TEST',
          name: 'Root Department',
          organizationId,
        },
        update: {},
      });

      // 直接通过数据库创建用户部门关系（更简单可靠）
      const testUser = await createTestUser({
        username: 'testuser_pos',
        email: 'testuser_pos@example.com',
        password: 'Test@123',
        displayName: 'Test User',
        status: 'ACTIVE',
        source: 'LOCAL',
      });

      // 创建用户部门关系，关联到岗位
      await prisma.userDepartment.create({
        data: {
          userId: testUser.id,
          departmentId: rootDept.id,
          organizationId,
          positionId,
          isPrimary: true,
          joinedAt: new Date(),
        },
      });

      // 尝试删除岗位
      const response = await request(app.getHttpServer())
        .delete(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(400);

      expect(response.body.success).toBe(false);
      expect(response.body.error.message).toContain('用户');
    });
  });

  describe('完整业务流程测试', () => {
    it('[API-POSITION-FLOW-001] 应该完成完整的岗位管理流程', async () => {
      // 1. 创建岗位
      const createResponse = await request(app.getHttpServer())
        .post('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          code: 'FLOW001',
          name: '流程测试岗位',
          level: 1,
          description: '测试完整流程',
        })
        .expect(201);

      const positionId = createResponse.body.data.id;

      // 2. 查询岗位详情
      const detailResponse = await request(app.getHttpServer())
        .get(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(detailResponse.body.data.code).toBe('FLOW001');

      // 3. 更新岗位
      await request(app.getHttpServer())
        .put(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({
          name: '高级流程测试岗位',
          level: 2,
        })
        .expect(200);

      // 4. 查询列表
      const listResponse = await request(app.getHttpServer())
        .get('/api/v1/positions')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

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

      // 5. 删除岗位
      await request(app.getHttpServer())
        .delete(`/api/v1/positions/${positionId}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      console.log('✅ 岗位管理完整流程测试通过');
    });
  });
});

