import { NotFoundException } from '@nestjs/common';
import { AnnualLeavePlanAdminService } from '../../../../src/modules/organization/dingtalk/annual-leave-plan-admin.service';
import { EMPLOYEE_INFO_FIELDS } from '../../../../src/modules/organization/dingtalk/constants';

describe('AnnualLeavePlanAdminService', () => {
  it('应返回指定员工的年假计划参数', async () => {
    const record = {
      userId: 'user001',
      employeeName: '张三',
      employeeNumber: 'E001',
      year: 2026,
      status: '正常',
      joinDate: new Date('2024-01-01T00:00:00Z'),
      workStartDate: new Date('2020-01-01T00:00:00Z'),
      adjustmentDays: 1.5,
      notCountDays: 2,
      totalDays: 5,
      releaseSchedule: [{ dayIndex: 1, releaseDate: '2026-03-01' }],
      lastCalculatedAt: new Date('2026-03-01T08:00:00Z'),
    };
    const prisma = {
      dingtalkAnnualLeaveReleasePlan: {
        findUnique: jest.fn().mockResolvedValue(record),
      },
    };
    const syncService = {
      refreshPlan: jest.fn(),
    };
    const yidaService = {
      searchForm: jest.fn(),
    };

    const service = new AnnualLeavePlanAdminService(
      prisma as any,
      syncService as any,
      yidaService as any,
    );

    const result = await service.getPlanSettings('user001', 2026);

    expect(prisma.dingtalkAnnualLeaveReleasePlan.findUnique).toHaveBeenCalledWith({
      where: {
        userId_year: {
          userId: 'user001',
          year: 2026,
        },
      },
    });
    expect(result).toMatchObject({
      userId: 'user001',
      employeeName: '张三',
      adjustmentDays: 1.5,
      notCountDays: 2,
      releaseSchedule: [{ dayIndex: 1, releaseDate: '2026-03-01' }],
    });
  });

  it('更新年假计划参数后应触发指定年份的重算', async () => {
    const record = {
      userId: 'user001',
      employeeName: '张三',
      employeeNumber: 'E001',
      year: 2026,
      status: '正常',
      joinDate: new Date('2024-01-01T00:00:00Z'),
      workStartDate: new Date('2020-01-01T00:00:00Z'),
      adjustmentDays: 0,
      notCountDays: 0,
      totalDays: 5,
      releaseSchedule: [],
      lastCalculatedAt: new Date('2026-03-01T08:00:00Z'),
    };
    const repo = {
      findUnique: jest.fn()
        .mockResolvedValueOnce(record)
        .mockResolvedValueOnce({
          ...record,
          status: '停薪留职',
          adjustmentDays: 2,
          notCountDays: 3,
        }),
      update: jest.fn().mockResolvedValue(undefined),
    };
    const prisma = {
      dingtalkAnnualLeaveReleasePlan: repo,
    };
    const syncService = {
      refreshPlan: jest.fn().mockResolvedValue({ success: true }),
    };
    const yidaService = {
      searchForm: jest.fn(),
    };

    const service = new AnnualLeavePlanAdminService(
      prisma as any,
      syncService as any,
      yidaService as any,
    );

    const result = await service.updatePlanSettings({
      userId: 'user001',
      year: 2026,
      status: '停薪留职',
      adjustmentDays: 2,
      notCountDays: 3,
      recalculate: true,
    });

    expect(repo.update).toHaveBeenCalledWith(
      expect.objectContaining({
        where: {
          userId_year: {
            userId: 'user001',
            year: 2026,
          },
        },
        data: expect.objectContaining({
          status: '停薪留职',
          adjustmentDays: 2,
          notCountDays: 3,
        }),
      }),
    );
    expect(syncService.refreshPlan).toHaveBeenCalledWith('user001', 2026);
    expect(result.status).toBe('停薪留职');
    expect(result.adjustmentDays).toBe(2);
    expect(result.notCountDays).toBe(3);
  });

  it('缺少本地年假计划时应创建占位记录', async () => {
    const repo = {
      findUnique: jest.fn()
        .mockResolvedValueOnce(null)
        .mockResolvedValueOnce({
          userId: 'user001',
          employeeName: '张三',
          employeeNumber: 'E001',
          year: 2026,
          status: '正常',
          joinDate: null,
          workStartDate: null,
          adjustmentDays: 0,
          notCountDays: 0,
          totalDays: 0,
          releaseSchedule: [],
          lastCalculatedAt: new Date('2026-03-01T08:00:00Z'),
        }),
      upsert: jest.fn().mockResolvedValue({
        userId: 'user001',
        employeeName: '张三',
        employeeNumber: 'E001',
        year: 2026,
        status: '正常',
        joinDate: null,
        workStartDate: null,
        adjustmentDays: 0,
        notCountDays: 0,
        totalDays: 0,
        releaseSchedule: [],
        lastCalculatedAt: new Date('2026-03-01T08:00:00Z'),
      }),
      update: jest.fn(),
    };
    const prisma = {
      dingtalkAnnualLeaveReleasePlan: repo,
    };
    const syncService = {
      refreshPlan: jest.fn(),
    };
    const yidaService = {
      searchForm: jest.fn().mockResolvedValue([
        {
          formData: {
            [EMPLOYEE_INFO_FIELDS.USER_ID]: 'user001',
            [EMPLOYEE_INFO_FIELDS.NAME]: '张三',
            [EMPLOYEE_INFO_FIELDS.NUMBER]: 'E001',
            [EMPLOYEE_INFO_FIELDS.START_DATE]: '',
            [EMPLOYEE_INFO_FIELDS.WORK_DATE]: '',
          },
        },
      ]),
    };

    const service = new AnnualLeavePlanAdminService(
      prisma as any,
      syncService as any,
      yidaService as any,
    );

    const result = await service.getPlanSettings('user001', 2026);

    expect(repo.upsert).toHaveBeenCalled();
    expect(result).toMatchObject({
      userId: 'user001',
      employeeName: '张三',
      totalDays: 0,
      releaseSchedule: [],
    });
  });

  it('员工不存在时应抛出异常', async () => {
    const prisma = {
      dingtalkAnnualLeaveReleasePlan: {
        findUnique: jest.fn().mockResolvedValue(null),
        upsert: jest.fn(),
        update: jest.fn(),
      },
    };
    const syncService = {
      refreshPlan: jest.fn(),
    };
    const yidaService = {
      searchForm: jest.fn().mockResolvedValue([]),
    };

    const service = new AnnualLeavePlanAdminService(
      prisma as any,
      syncService as any,
      yidaService as any,
    );

    await expect(service.getPlanSettings('user001', 2026)).rejects.toBeInstanceOf(NotFoundException);
  });
});
