package com.magistr.app.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.magistr.app.config.auth.AuthenticatedUser;
import com.magistr.app.config.auth.AuthorizationInterceptor;
import com.magistr.app.config.auth.JwtTokenService;
import com.magistr.app.config.tenant.TenantContext;
import com.magistr.app.model.EducationForm;
import com.magistr.app.model.LifecycleEntity;
import com.magistr.app.model.Role;
import com.magistr.app.repository.AcademicCalendarRepository;
import com.magistr.app.repository.EducationFormRepository;
import com.magistr.app.repository.GroupRepository;
import com.magistr.app.repository.SpecialtiesRepository;
import com.magistr.app.repository.SpecialtyProfileRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.util.List;
import java.util.Optional;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class EducationOfficeRoleMatrixTest {

    private static final String TENANT = "tenant-role-matrix";
    private static final String TOKEN = "education-office-token";

    private MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        TenantContext.clear();
        TenantContext.setCurrentTenant(TENANT);

        JwtTokenService jwtTokenService = mock(JwtTokenService.class);
        when(jwtTokenService.authenticate(TOKEN, TENANT)).thenReturn(Optional.of(
                new AuthenticatedUser(10L, "учебный.отдел", Role.EDUCATION_OFFICE, null)
        ));

        SpecialtiesRepository specialtiesRepository = mock(SpecialtiesRepository.class);
        SpecialtyProfileRepository profileRepository = mock(SpecialtyProfileRepository.class);
        when(specialtiesRepository.findByStatusNot(LifecycleEntity.STATUS_ARCHIVED)).thenReturn(List.of());
        when(specialtiesRepository.existsById(1L)).thenReturn(true);
        when(profileRepository.findBySpecialityIdOrderByNameAsc(1L)).thenReturn(List.of());
        SpecialityController specialityController = new SpecialityController(
                specialtiesRepository,
                profileRepository
        );

        EducationFormRepository educationFormRepository = mock(EducationFormRepository.class);
        GroupRepository groupRepository = mock(GroupRepository.class);
        AcademicCalendarRepository calendarRepository = mock(AcademicCalendarRepository.class);
        when(educationFormRepository.findAllByOrderByNameAsc()).thenReturn(List.of());
        when(educationFormRepository.findByName("Очная")).thenReturn(Optional.empty());
        when(educationFormRepository.save(any(EducationForm.class))).thenAnswer(invocation -> {
            EducationForm form = invocation.getArgument(0);
            form.setId(20L);
            return form;
        });
        when(educationFormRepository.existsById(20L)).thenReturn(true);
        when(groupRepository.findByEducationFormId(20L)).thenReturn(List.of());
        when(calendarRepository.countByStudyFormId(20L)).thenReturn(0L);
        EducationFormController educationFormController = new EducationFormController(
                educationFormRepository,
                groupRepository,
                calendarRepository
        );

        mockMvc = MockMvcBuilders
                .standaloneSetup(specialityController, educationFormController)
                .addInterceptors(new AuthorizationInterceptor(jwtTokenService, new ObjectMapper()))
                .build();
    }

    @AfterEach
    void clearContext() {
        TenantContext.clear();
    }

    @Test
    void educationOfficeInitializesCalendarAndManagesEducationFormsWithoutForbidden() throws Exception {
        mockMvc.perform(get("/api/specialties").header("Authorization", bearer()))
                .andExpect(status().isOk());
        mockMvc.perform(get("/api/specialties/1/profiles").header("Authorization", bearer()))
                .andExpect(status().isOk());
        mockMvc.perform(get("/api/education-forms").header("Authorization", bearer()))
                .andExpect(status().isOk());
        mockMvc.perform(post("/api/education-forms")
                        .header("Authorization", bearer())
                        .contentType("application/json")
                        .content("{\"name\":\"Очная\"}"))
                .andExpect(status().isOk());
        mockMvc.perform(delete("/api/education-forms/20").header("Authorization", bearer()))
                .andExpect(status().isOk());
    }

    @Test
    void educationOfficeStillCannotModifySpecialties() throws Exception {
        mockMvc.perform(post("/api/specialties")
                        .header("Authorization", bearer())
                        .contentType("application/json")
                        .content("{\"specialityName\":\"Тест\",\"specialityCode\":\"01\"}"))
                .andExpect(status().isForbidden());
    }

    private String bearer() {
        return "Bearer " + TOKEN;
    }
}
