package com.magistr.app.controller;

import com.magistr.app.config.auth.AuthContext;
import com.magistr.app.config.auth.AuthenticatedUser;
import com.magistr.app.dto.UserResponse;
import com.magistr.app.model.Department;
import com.magistr.app.model.LifecycleEntity;
import com.magistr.app.model.Role;
import com.magistr.app.model.Subject;
import com.magistr.app.model.TeacherDepartmentAssignment;
import com.magistr.app.model.User;
import com.magistr.app.repository.SubjectCommentRepository;
import com.magistr.app.repository.SubjectRepository;
import com.magistr.app.repository.DepartmentRepository;
import com.magistr.app.repository.TeacherCreationRequestRepository;
import com.magistr.app.repository.TeacherDepartmentAssignmentRepository;
import com.magistr.app.repository.UserRepository;
import com.magistr.app.service.ScheduleQueryService;
import com.magistr.app.service.SubjectImportService;
import com.magistr.app.service.TeacherDepartmentService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;

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

class DepartmentWorkspaceControllerTest {

    @AfterEach
    void clearAuthContext() {
        AuthContext.clear();
    }

    @Test
    void commentsRejectSubjectWithoutDepartmentForDepartmentUserWithoutNpe() {
        SubjectRepository subjectRepository = mock(SubjectRepository.class);
        Subject subject = new Subject();
        subject.setId(10L);
        subject.setDepartmentId(null);
        when(subjectRepository.findById(10L)).thenReturn(Optional.of(subject));
        DepartmentWorkspaceController controller = new DepartmentWorkspaceController(
                subjectRepository,
                mock(SubjectCommentRepository.class),
                mock(UserRepository.class),
                mock(DepartmentRepository.class),
                mock(TeacherDepartmentAssignmentRepository.class),
                mock(TeacherCreationRequestRepository.class),
                mock(ScheduleQueryService.class),
                mock(TeacherDepartmentService.class),
                mock(SubjectImportService.class)
        );
        AuthContext.setCurrentUser(new AuthenticatedUser(1L, "кафедра", Role.DEPARTMENT, 2L));

        var response = controller.getComments(10L);

        assertThat(response.getStatusCode().value()).isEqualTo(404);
    }

    @Test
    void teachersUseDatedAssignmentsWithoutLegacyFallback() {
        UserRepository userRepository = mock(UserRepository.class);
        TeacherDepartmentAssignmentRepository assignmentRepository = mock(TeacherDepartmentAssignmentRepository.class);
        TeacherDepartmentService teacherDepartmentService = mock(TeacherDepartmentService.class);
        User assignedTeacher = user(10L, "assigned", "Петров Препод Петрович", 2L);
        User directTeacher = user(11L, "direct", "Препод Тест Тестович", 1L);
        when(teacherDepartmentService.findTeachersForDepartmentAtDate(1L, LocalDate.now()))
                .thenReturn(List.of(directTeacher, assignedTeacher));
        DepartmentWorkspaceController controller = new DepartmentWorkspaceController(
                mock(SubjectRepository.class),
                mock(SubjectCommentRepository.class),
                userRepository,
                mock(DepartmentRepository.class),
                assignmentRepository,
                mock(TeacherCreationRequestRepository.class),
                mock(ScheduleQueryService.class),
                teacherDepartmentService,
                mock(SubjectImportService.class)
        );

        List<UserResponse> teachers = controller.getTeachers(1L);

        assertThat(teachers).extracting(UserResponse::getFullName)
                .containsExactlyInAnyOrder("Петров Препод Петрович", "Препод Тест Тестович");
    }

    @Test
    void departmentCanAddExistingTeacherAsSecondaryAssignment() {
        UserRepository userRepository = mock(UserRepository.class);
        DepartmentRepository departmentRepository = mock(DepartmentRepository.class);
        TeacherDepartmentAssignmentRepository assignmentRepository = mock(TeacherDepartmentAssignmentRepository.class);
        User teacher = user(20L, "teacher", "Иванов Иван Иванович", 2L);
        Department department = new Department(1L, "Кафедра ИБ", 1L);
        when(userRepository.findById(20L)).thenReturn(Optional.of(teacher));
        when(departmentRepository.findById(1L)).thenReturn(Optional.of(department));
        when(assignmentRepository.existsActiveAssignment(20L, 1L, LocalDate.now())).thenReturn(false);
        DepartmentWorkspaceController controller = new DepartmentWorkspaceController(
                mock(SubjectRepository.class),
                mock(SubjectCommentRepository.class),
                userRepository,
                departmentRepository,
                assignmentRepository,
                mock(TeacherCreationRequestRepository.class),
                mock(ScheduleQueryService.class),
                mock(TeacherDepartmentService.class),
                mock(SubjectImportService.class)
        );
        AuthContext.setCurrentUser(new AuthenticatedUser(3L, "department", Role.DEPARTMENT, 1L));

        var response = controller.addTeacherToDepartment(20L, Map.of("comment", "Совместительство"));

        assertThat(response.getStatusCode().value()).isEqualTo(200);
        ArgumentCaptor<TeacherDepartmentAssignment> captor = ArgumentCaptor.forClass(TeacherDepartmentAssignment.class);
        verify(assignmentRepository).save(captor.capture());
        TeacherDepartmentAssignment saved = captor.getValue();
        assertThat(saved.getTeacher()).isEqualTo(teacher);
        assertThat(saved.getDepartment()).isEqualTo(department);
        assertThat(saved.getPrimaryAssignment()).isFalse();
        assertThat(saved.getCreatedBy()).isEqualTo(3L);
    }

    private TeacherDepartmentAssignment assignment(User teacher, Long departmentId) {
        Department department = new Department(departmentId, "Кафедра", departmentId);
        TeacherDepartmentAssignment assignment = new TeacherDepartmentAssignment();
        assignment.setTeacher(teacher);
        assignment.setDepartment(department);
        assignment.setValidFrom(LocalDate.now());
        return assignment;
    }

    private User user(Long id, String username, String fullName, Long departmentId) {
        User user = new User();
        user.setId(id);
        user.setUsername(username);
        user.setRole(Role.TEACHER);
        user.setFullName(fullName);
        user.setJobTitle("Доцент");
        user.setDepartmentId(departmentId);
        return user;
    }
}
