import { BadRequestException } from '@nestjs/common';
import { LessonAttendanceSyncService } from './lesson-attendance-sync.service';

const lesson = {
  schedule: {
    id: 4,
    classId: 8,
    startTime: '22:00',
    endTime: '01:00',
    attendanceAdvanceMinutes: 30,
  },
  session: null,
  records: [],
};

const createService = () => {
  const attendanceService = {
    getLessonAttendance: jest.fn().mockResolvedValue(lesson),
    getTeacherClassDingUserIds: jest.fn().mockResolvedValue(['ding-1', 'ding-2']),
    getLessonAttendanceImportDateRange: jest.fn().mockReturnValue({
      startDate: '2026-07-11',
      endDate: '2026-07-12',
    }),
    createLessonAttendanceFromDingTalk: jest.fn().mockResolvedValue({
      ...lesson,
      session: { id: 90, status: 'in_progress' },
    }),
  };
  const importService = {
    importFromDingTalk: jest.fn().mockResolvedValue({
      success: true,
      imported: 3,
      skipped: 0,
      matched: 2,
      errors: [],
      duration: 10,
    }),
  };
  return {
    service: new LessonAttendanceSyncService(attendanceService as never, importService as never),
    attendanceService,
    importService,
  };
};

describe('LessonAttendanceSyncService', () => {
  it('owns the complete refresh recipe and returns attendance with import statistics', async () => {
    const { service, attendanceService, importService } = createService();

    const result = await service.syncLesson({
      scheduleId: 4,
      lessonDate: '2026-07-11',
      actorId: 21,
      canManageAll: false,
      mode: 'refresh',
    });

    expect(attendanceService.getTeacherClassDingUserIds).toHaveBeenCalledWith(
      21,
      8,
      false,
      '2026-07-11',
    );
    expect(importService.importFromDingTalk).toHaveBeenCalledWith({
      startDate: '2026-07-11',
      endDate: '2026-07-12',
      userIds: ['ding-1', 'ding-2'],
      autoMatch: true,
      userId: 21,
    });
    expect(attendanceService.createLessonAttendanceFromDingTalk).toHaveBeenCalledWith(
      4,
      '2026-07-11',
      21,
      false,
    );
    expect(result).toMatchObject({
      attendance: { session: { id: 90 } },
      imported: 3,
      matched: 2,
    });
  });

  it('finalizes only after a complete import', async () => {
    const { service, attendanceService } = createService();

    await service.syncLesson({
      scheduleId: 4,
      lessonDate: '2026-07-11',
      actorId: 21,
      canManageAll: true,
      mode: 'finalize',
    });

    expect(attendanceService.createLessonAttendanceFromDingTalk).toHaveBeenCalledWith(
      4,
      '2026-07-11',
      21,
      true,
    );
  });

  it('rejects partial imports before changing lesson attendance', async () => {
    const { service, attendanceService, importService } = createService();
    importService.importFromDingTalk.mockResolvedValue({
      success: true,
      imported: 1,
      matched: 1,
      errors: ['one batch failed'],
    });

    await expect(
      service.syncLesson({
        scheduleId: 4,
        lessonDate: '2026-07-11',
        actorId: 21,
        canManageAll: false,
        mode: 'refresh',
      }),
    ).rejects.toBeInstanceOf(BadRequestException);
    expect(attendanceService.createLessonAttendanceFromDingTalk).not.toHaveBeenCalled();
  });
});
