/**
 * IAM Access Review 集成测试（PR #138 / 规则 §5.3.15）
 *
 * 覆盖：
 * - listPending(days) 阈值
 * - approve（保留，更新 lastReviewedAt）
 * - revoke（删除 user_role + audit）
 * - 普通员工不能调用（权限护栏）
 */
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 { createTestUser } from '../../helpers/factories/user.factory';
import { setupIntegrationTest } from '../../helpers/test-setup.helper';

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

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

  beforeEach(async () => {
    const ctx = await setupIntegrationTest(app, prisma);
    adminToken = ctx.adminToken;
  });

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

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

  /** 建一个用户 + 一个角色，绑定关系 lastReviewedAt 设为 olderDays 天前 */
  async function createOverdueUserRole(olderDays: number) {
    const user = await createTestUser({
      username: `ar_user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
      email: `ar_${Date.now()}@e.com`,
      password: 'Test@123',
      status: 'ACTIVE',
      source: 'LOCAL',
    });
    const role = await prisma.role.upsert({
      where: { code: `__ar_test_role_${Date.now()}` },
      create: {
        code: `__ar_test_role_${Date.now()}`,
        name: 'AR Test Role',
        description: 'integration',
        isBuiltIn: false,
        enabled: true,
      },
      update: {},
    });
    const ur = await prisma.userRole.create({
      data: {
        userId: user.id,
        roleId: role.id,
        lastReviewedAt: new Date(Date.now() - olderDays * 86_400_000),
      },
    });
    return { user, role, ur };
  }

  describe('GET /iam/access-review/pending - 超期列表', () => {
    it('[API-IAM-AR-001] 默认 90 天阈值，超期项进入待复核', async () => {
      const { ur } = await createOverdueUserRole(100);

      const res = await request(app.getHttpServer())
        .get('/api/v1/iam/access-review/pending?days=90')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(res.body.data.some((x: { id: string }) => x.id === ur.id)).toBe(true);
    });

    it('[API-IAM-AR-002] 60 天阈值下，70 天前的项命中', async () => {
      const { ur } = await createOverdueUserRole(70);
      const res = await request(app.getHttpServer())
        .get('/api/v1/iam/access-review/pending?days=60')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);
      expect(res.body.data.some((x: { id: string }) => x.id === ur.id)).toBe(true);
    });

    it('[API-IAM-AR-003] 普通员工无 access_review:manage → 403', async () => {
      const empUsername = `ar_emp_${Date.now()}`;
      const empPassword = 'Emp@1234';
      await createTestUser({
        username: empUsername,
        email: `${empUsername}@e.com`,
        password: empPassword,
        status: 'ACTIVE',
        source: 'LOCAL',
      });
      const login = await request(app.getHttpServer())
        .post('/api/v1/auth/login')
        .send({ username: empUsername, password: empPassword })
        .expect(200);

      await request(app.getHttpServer())
        .get('/api/v1/iam/access-review/pending?days=90')
        .set('Authorization', `Bearer ${login.body.data.accessToken}`)
        .expect(403);
    });
  });

  describe('POST /iam/access-review/:id/approve - 保留', () => {
    it('[API-IAM-AR-010] approve 后 lastReviewedAt 刷新到当下，列表不再包含', async () => {
      const { ur } = await createOverdueUserRole(100);

      await request(app.getHttpServer())
        .post(`/api/v1/iam/access-review/${ur.id}/approve`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ comment: 'still needed' })
        .expect(201);

      const after = await prisma.userRole.findUnique({ where: { id: ur.id } });
      expect(after?.lastReviewedAt!.getTime()).toBeGreaterThan(
        Date.now() - 60_000,
      );
      expect(after?.reviewComment).toBe('still needed');
    });
  });

  describe('POST /iam/access-review/:id/revoke - 撤销', () => {
    it('[API-IAM-AR-020] revoke 后 user_role 真删，audit_log 记录 DELETE', async () => {
      const { ur } = await createOverdueUserRole(100);

      await request(app.getHttpServer())
        .post(`/api/v1/iam/access-review/${ur.id}/revoke`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ comment: 'no longer needed' })
        .expect(201);

      const after = await prisma.userRole.findUnique({ where: { id: ur.id } });
      expect(after).toBeNull();

      const audits = await prisma.iamAuditLog.findMany({
        where: { resource: 'UserRole', action: 'DELETE', targetId: ur.id },
      });
      expect(audits.length).toBeGreaterThanOrEqual(1);
    });
  });
});
