package com.magistr.app.service;

import com.magistr.app.dto.RenderedLessonDto;
import com.magistr.app.model.Classroom;
import com.magistr.app.model.Role;
import com.magistr.app.model.ScheduleOverride;
import com.magistr.app.model.ScheduleParity;
import com.magistr.app.model.ScheduleRuleSlot;
import com.magistr.app.model.TimeSlot;
import com.magistr.app.model.User;
import com.magistr.app.repository.GroupRepository;
import com.magistr.app.repository.ScheduleOverrideRepository;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

class ScheduleQueryServiceOverrideTest {

    private static final LocalDate DATE = LocalDate.of(2026, 9, 1);

    @Test
    void appliesAllReplacementFieldsToProvidedDaySnapshot() {
        ScheduleQueryService service = service();
        RenderedLessonDto base = lesson();
        ScheduleOverride override = override("MOVE");

        TimeSlot newTimeSlot = new TimeSlot();
        newTimeSlot.setId(2L);
        newTimeSlot.setOrderNumber(2);
        newTimeSlot.setStartTime(LocalTime.of(10, 40));
        newTimeSlot.setEndTime(LocalTime.of(12, 10));
        override.setNewTimeSlot(newTimeSlot);

        Classroom newClassroom = new Classroom();
        newClassroom.setId(22L);
        newClassroom.setName("Б-202");
        override.setNewClassroom(newClassroom);

        User newTeacher = new User();
        newTeacher.setId(12L);
        newTeacher.setRole(Role.TEACHER);
        newTeacher.setFullName("Новый преподаватель");
        override.setNewTeacher(newTeacher);
        override.setNewLessonFormat("Онлайн");

        List<RenderedLessonDto> result = service.buildEffectiveDayForAllGroups(
                List.of(base),
                DATE,
                List.of(override)
        );

        assertThat(result).singleElement().satisfies(lesson -> {
            assertThat(lesson.timeSlotId()).isEqualTo(2L);
            assertThat(lesson.startTime()).isEqualTo(LocalTime.of(10, 40));
            assertThat(lesson.endTime()).isEqualTo(LocalTime.of(12, 10));
            assertThat(lesson.teacherId()).isEqualTo(12L);
            assertThat(lesson.teacherName()).isEqualTo("Новый преподаватель");
            assertThat(lesson.classroomId()).isEqualTo(22L);
            assertThat(lesson.classroomName()).isEqualTo("Б-202");
            assertThat(lesson.lessonFormat()).isEqualTo("Онлайн");
            assertThat(lesson.groupIds()).containsExactly(31L);
        });
    }

    @Test
    void removesCancelledOccurrenceFromProvidedDaySnapshot() {
        ScheduleQueryService service = service();

        List<RenderedLessonDto> result = service.buildEffectiveDayForAllGroups(
                List.of(lesson()),
                DATE,
                List.of(override("CANCEL"))
        );

        assertThat(result).isEmpty();
    }

    @Test
    void ignoresOverrideForAnotherDate() {
        ScheduleQueryService service = service();
        ScheduleOverride override = override("CANCEL");
        override.setLessonDate(DATE.plusDays(1));

        List<RenderedLessonDto> result = service.buildEffectiveDayForAllGroups(
                List.of(lesson()),
                DATE,
                List.of(override)
        );

        assertThat(result).singleElement().extracting(RenderedLessonDto::scheduleRuleSlotId).isEqualTo(101L);
    }

    private ScheduleQueryService service() {
        return new ScheduleQueryService(
                mock(ScheduleGeneratorService.class),
                mock(GroupRepository.class),
                mock(ScheduleOverrideRepository.class),
                mock(StudentGroupLifecycleService.class)
        );
    }

    private ScheduleOverride override(String action) {
        ScheduleRuleSlot baseSlot = new ScheduleRuleSlot();
        baseSlot.setId(101L);
        ScheduleOverride override = new ScheduleOverride();
        override.setBaseRuleSlot(baseSlot);
        override.setLessonDate(DATE);
        override.setAction(action);
        return override;
    }

    private RenderedLessonDto lesson() {
        return new RenderedLessonDto(
                900L,
                101L,
                DATE,
                2,
                "Вторник",
                1,
                ScheduleParity.BOTH,
                1L,
                1,
                LocalTime.of(9, 0),
                LocalTime.of(10, 30),
                501L,
                "Тестовая дисциплина",
                11L,
                "Исходный преподаватель",
                21L,
                "А-101",
                601L,
                "Лекция",
                "Очно",
                null,
                null,
                List.of(),
                List.of(),
                List.of(31L),
                List.of("Группа 31"),
                "Т",
                2,
                0,
                0,
                ScheduleParity.BOTH
        );
    }
}
