import { DingTalkService } from '../integration/dingtalk.service';


describe('DingTalkService — attendance records', () => {
  const originalAppKey = process.env.DINGTALK_APP_KEY;
  const originalAppSecret = process.env.DINGTALK_APP_SECRET;
  let service: DingTalkService;

  beforeEach(() => {
    process.env.DINGTALK_APP_KEY = 'test-app-key';
    process.env.DINGTALK_APP_SECRET = 'test-app-secret';
    service = new DingTalkService({} as never, {} as never);
    Object.assign(service, {
      accessToken: 'test-token',
      accessTokenCredentialKey: 'test-app-key:test-app-secret',
      tokenExpiresAt: Date.now() + 3_600_000,
    });
  });

  afterEach(() => {
    jest.restoreAllMocks();
    global.fetch = undefined as unknown as typeof fetch;
  });

  afterAll(() => {
    if (originalAppKey === undefined) delete process.env.DINGTALK_APP_KEY;
    else process.env.DINGTALK_APP_KEY = originalAppKey;
    if (originalAppSecret === undefined) delete process.env.DINGTALK_APP_SECRET;
    else process.env.DINGTALK_APP_SECRET = originalAppSecret;
  });

  it('sends the required userIds and does not send unsupported offset/limit fields', async () => {
    global.fetch = jest.fn().mockResolvedValue({
      json: jest.fn().mockResolvedValue({ errcode: 0, errmsg: 'ok', recordresult: [] }),
    }) as jest.MockedFunction<typeof fetch>;

    await service.fetchAttendanceResults({
      startDate: '2026-07-01',
      endDate: '2026-07-07',
      userIds: ['ding-1', 'ding-2'],
    });

    expect(JSON.parse((global.fetch as jest.Mock).mock.calls[0][1].body)).toEqual({
      checkDateFrom: '2026-07-01 00:00:00',
      checkDateTo: '2026-07-07 23:59:59',
      userIds: ['ding-1', 'ding-2'],
    });
  });

  it('rejects missing userIds before calling DingTalk', async () => {
    await expect(
      service.fetchAttendanceResults({
        startDate: '2026-07-01',
        endDate: '2026-07-01',
      }),
    ).rejects.toThrow('userIds');
    expect(global.fetch).toBeUndefined();
  });

  it('keeps DingTalk work dates in China local time', async () => {
    global.fetch = jest.fn().mockResolvedValue({
      json: jest.fn().mockResolvedValue({
        errcode: 0,
        errmsg: 'ok',
        recordresult: [
          {
            id: 1,
            userId: 'ding-1',
            workDate: Date.parse('2026-07-12T00:00:00+08:00'),
            userCheckTime: Date.parse('2026-07-12T21:05:00+08:00'),
            sourceType: 'ATM',
            checkType: 'OnDuty',
            deviceName: '东门考勤机',
            deviceId: 'ATM-01',
            timeResult: 'Normal',
          },
        ],
      }),
    }) as jest.MockedFunction<typeof fetch>;

    const [record] = await service.fetchAttendanceResults({
      startDate: '2026-07-12',
      endDate: '2026-07-12',
      userIds: ['ding-1'],
    });

    expect(record.workDate).toBe('2026-07-12');
    expect(record).toEqual(
      expect.objectContaining({
        checkType: 'OnDuty',
        sourceType: 'ATM',
        deviceName: '东门考勤机',
        deviceId: 'ATM-01',
      }),
    );
  });

  it('fetches approved leave approvals from the daily attendance data API', async () => {
    global.fetch = jest.fn().mockResolvedValue({
      json: jest.fn().mockResolvedValue({
        errcode: 0,
        errmsg: 'ok',
        result: {
          userid: 'ding-1',
          work_date: '2026-07-12 00:00:00',
          approve_list: [
            {
              procInst_id: 'PRO-LEAVE-1',
              tag_name: '请假',
              sub_type: '事假',
              biz_type: 3,
              begin_time: '2026-07-12 08:00:00',
              end_time: '2026-07-12 12:00:00',
              gmt_finished: '2026-07-11 18:00:00',
              duration: '0.5',
              duration_unit: 'day',
            },
            {
              // 审批中（无 gmt_finished）的请假不应返回
              procInst_id: 'PRO-LEAVE-2',
              tag_name: '请假',
              sub_type: '病假',
              biz_type: 3,
              begin_time: '2026-07-12 08:00:00',
              end_time: '2026-07-12 12:00:00',
              duration: '0.5',
              duration_unit: 'day',
            },
            {
              // 出差（biz_type=2）不应返回
              procInst_id: 'PRO-TRIP-1',
              tag_name: '出差',
              sub_type: '出差',
              biz_type: 2,
              begin_time: '2026-07-12 08:00:00',
              end_time: '2026-07-12 18:00:00',
              gmt_finished: '2026-07-11 18:00:00',
            },
          ],
        },
      }),
    }) as jest.MockedFunction<typeof fetch>;

    const leaves = await service.fetchDailyLeaveStatus('ding-1', '2026-07-12');

    expect(JSON.parse((global.fetch as jest.Mock).mock.calls[0][1].body)).toEqual({
      userid: 'ding-1',
      work_date: '2026-07-12 00:00:00',
    });
    expect(leaves).toHaveLength(1);
    expect(leaves[0]).toEqual(
      expect.objectContaining({
        userId: 'ding-1',
        workDate: '2026-07-12',
        procInstId: 'PRO-LEAVE-1',
        leaveType: '事假',
        tagName: '请假',
        beginTime: new Date('2026-07-12T08:00:00+08:00'),
        endTime: new Date('2026-07-12T12:00:00+08:00'),
        approvedAt: new Date('2026-07-11T18:00:00+08:00'),
        duration: '0.5',
        durationUnit: 'day',
      }),
    );
  });
});
