/**
 * Dingtalk Employee Tenure Integration Tests
 *
 * 验证司龄计算口径（2026-05-08 与 HR 确认后回退 PR #241）：
 *   累计司龄 = Σ countInTenure 段天数 (leaveDate − joinDate)
 *   - 离职到再入职的 gap 自动排除
 *   - 停薪留职**计入司龄**，不扣减
 *   - 停薪留职 CRUD 不影响 tenure_days 缓存
 *
 * 直接拿 service 跑（纯计算逻辑），不走 HTTP/auth 链路。
 */

import { INestApplication } from '@nestjs/common';
import { PrismaService } from '@/core/database/prisma/prisma.service';
import { EmployeeManagementService } from '@/modules/organization/dingtalk/employee-management.service';
import { createTestApp } from '../../helpers/app.helper';

const TEST_USER_PREFIX = 't_tenure_';

const dateOnly = (s: string) => new Date(`${s}T00:00:00.000Z`);

describe('Dingtalk Employee Tenure 集成测试', () => {
  let app: INestApplication;
  let prisma: PrismaService;
  let svc: EmployeeManagementService;
  let userId: string;

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

  beforeEach(async () => {
    userId = `${TEST_USER_PREFIX}${Date.now()}_${Math.floor(Math.random() * 1e6)}`;
    await (prisma as any).dingtalkEmployee.create({
      data: { userId, name: 'Tenure Test', joinDate: dateOnly('2020-01-01') },
    });
  });

  afterEach(async () => {
    await (prisma as any).dingtalkEmployeeSuspensionPeriod.deleteMany({ where: { userId } });
    await (prisma as any).dingtalkEmployeeEmploymentPeriod.deleteMany({ where: { userId } });
    await (prisma as any).dingtalkEmployee.deleteMany({ where: { userId } });
  });

  afterAll(async () => {
    await (prisma as any).dingtalkEmployeeSuspensionPeriod.deleteMany({
      where: { userId: { startsWith: TEST_USER_PREFIX } },
    });
    await (prisma as any).dingtalkEmployeeEmploymentPeriod.deleteMany({
      where: { userId: { startsWith: TEST_USER_PREFIX } },
    });
    await (prisma as any).dingtalkEmployee.deleteMany({
      where: { userId: { startsWith: TEST_USER_PREFIX } },
    });
    await app.close();
  });

  describe('[TENURE-001] 单段在职 + 停薪 → 停薪不扣，全段计入', () => {
    it('停薪留职区间不影响司龄天数', async () => {
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2024-01-01',
        leaveDate: '2024-12-31',
        countInTenure: true,
      });
      await svc.addSuspensionPeriod(userId, {
        startDate: '2024-04-01',
        endDate: '2024-04-30',
      });

      const asOf = dateOnly('2024-12-31');
      const result = await svc.calculateTenureDays(userId, asOf);

      // 365 天全计入，停薪不扣
      expect(result.totalDays).toBe(365);
      expect(result.source).toBe('periods');
    });
  });

  describe('[TENURE-002] 离职再入职 → gap 天数自动排除', () => {
    it('两段在职之间的 gap 不被累加', async () => {
      // 段 1：2022-01-01 → 2022-12-31 = floor((end-start)/86400000) = 364 天（非闰年）
      // gap：  2023-01-01 → 2023-12-31（一年离职，不应计入）
      // 段 2：2024-01-01 → 2024-12-31 = 365 天（闰年）
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2022-01-01',
        leaveDate: '2022-12-31',
        countInTenure: true,
      });
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2024-01-01',
        leaveDate: '2024-12-31',
        countInTenure: true,
      });

      const asOf = dateOnly('2025-01-01');
      const result = await svc.calculateTenureDays(userId, asOf);

      // 364 + 365 = 729，gap 那一年不算
      expect(result.totalDays).toBe(364 + 365);
    });
  });

  describe('[TENURE-003] countInTenure=false 段不计入', () => {
    it('未勾选计入司龄的段被跳过', async () => {
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2024-01-01',
        leaveDate: '2024-06-30',
        countInTenure: true,
      });
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2024-07-01',
        leaveDate: '2024-12-31',
        countInTenure: false,
      });

      const asOf = dateOnly('2024-12-31');
      const result = await svc.calculateTenureDays(userId, asOf);

      // 仅段 1 计入：(06-30 − 01-01) = 181 天
      expect(result.totalDays).toBe(181);
    });
  });

  describe('[TENURE-004] 停薪 CRUD 不触发 tenure_days 重算', () => {
    it('add/update/delete suspension 后 dingtalk_employees.tenure_days 不变', async () => {
      await svc.addEmploymentPeriod(userId, {
        joinDate: '2024-01-01',
        leaveDate: '2024-12-31',
        countInTenure: true,
      });

      let emp = await (prisma as any).dingtalkEmployee.findUnique({ where: { userId } });
      const before = emp.tenureDays;
      expect(before).toBe(365);

      const created = await svc.addSuspensionPeriod(userId, {
        startDate: '2024-04-01',
        endDate: '2024-04-30',
      });
      emp = await (prisma as any).dingtalkEmployee.findUnique({ where: { userId } });
      expect(emp.tenureDays).toBe(before);

      await svc.updateSuspensionPeriod(created.id, {
        startDate: '2024-04-01',
        endDate: '2024-06-30',
      });
      emp = await (prisma as any).dingtalkEmployee.findUnique({ where: { userId } });
      expect(emp.tenureDays).toBe(before);

      await svc.deleteSuspensionPeriod(created.id);
      emp = await (prisma as any).dingtalkEmployee.findUnique({ where: { userId } });
      expect(emp.tenureDays).toBe(before);
    });
  });

  describe('[TENURE-005] 无 employment_periods 时回退 join_date', () => {
    it('source=joinDate 路径下也不扣停薪', async () => {
      await (prisma as any).dingtalkEmployee.update({
        where: { userId },
        data: { joinDate: dateOnly('2024-01-01') },
      });
      await svc.addSuspensionPeriod(userId, {
        startDate: '2024-06-01',
        endDate: '2024-06-30',
      });

      const asOf = dateOnly('2024-12-31');
      const result = await svc.calculateTenureDays(userId, asOf);

      expect(result.source).toBe('joinDate');
      expect(result.totalDays).toBe(365);
    });
  });
});
