package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;

import org.instancio.Instancio;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.ImportDonneesEntreePort;
import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.DonneesEntreeRest;
import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter.SaveDonneesEntreeAdapter;
import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.DonneesEntreeRestMapper;
import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.DonneesEntreeRestMapperImpl;
import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementPostSaveService;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.ResourceUtils;
import org.springframework.web.server.ResponseStatusException;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class ImportCSVControllerTest {

    @InjectMocks
    private ImportCSVController importCSVController;

    @Mock
    ImportDonneesEntreePort importDonneesEntreePort;

    @Mock
    SaveDonneesEntreeAdapter saveDonneesEntreeAdapter;

    DonneesEntreeRestMapper donneesEntreeMapper = new DonneesEntreeRestMapperImpl();

    @Mock
    ErrorManagementPostSaveService errorManagementPostSaveService;

    @BeforeEach
    public void init() {
        MockitoAnnotations.openMocks(this);
        importCSVController = new ImportCSVController(donneesEntreeMapper, importDonneesEntreePort, saveDonneesEntreeAdapter, errorManagementPostSaveService);
    }

    @Test
    void importJson_shouldThrowExceptionWithNotImplemented() {
        var donneesTests = Instancio.of(DonneesEntreeRest.class).create();
        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importJson(donneesTests));

        assertEquals(HttpStatus.NOT_IMPLEMENTED, exception.getStatusCode());
        assertEquals("Cette méthode d'import n'a pas encore été implémenté.", exception.getReason());
    }

    @Test
    void importCSV_onNullFiles_shouldThrowResponseStatusExceptionWithBadRequest() {
        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", null, null, null, null, null, null));

        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
        assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason());
    }

    @Test
    void importCSV_onEmptyFiles_shouldThrowResponseStatusExceptionWithBadRequest() {
        MockMultipartFile csvDataCenters = new MockMultipartFile("csvDataCenterVide.csv", new byte[]{});
        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementsVide.csv", new byte[]{});
        MockMultipartFile csvEquipementsVirtuels = new MockMultipartFile("csvEquipementVirtuelVide.csv", new byte[]{});
        MockMultipartFile csvApplications = new MockMultipartFile("csvApplicationVide.csv", new byte[]{});
        MockMultipartFile csvMessagerie = new MockMultipartFile("csvMessagerieVide.csv", new byte[]{});
        MockMultipartFile csvEntite = new MockMultipartFile("csvEntiteVide.csv", new byte[]{});

        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));

        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
        assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason());
    }

    @ParameterizedTest
    @NullAndEmptySource
    void importCSV_whenNomLotIsNullOrBlank_shouldThrowResponseStatusExceptionWithBadRequest(String nomLot) throws IOException {
        MockMultipartFile csvDataCenters = null;
        InputStream fileEquipement = new FileInputStream(ResourceUtils.getFile("target/test-classes/equipementPhysique.csv"));
        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement);
        MockMultipartFile csvEquipementsVirtuels = null;
        MockMultipartFile csvApplications = null;
        MockMultipartFile csvMessagerie = null;
        MockMultipartFile csvEntite = null;

        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV(nomLot, "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));

        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
        assertEquals("Le nom du Lot ne peut être pas vide", exception.getReason());
    }

    @Test
    void importCSV_whenDateLotBadFormat_shouldThrowResponseStatusExceptionWithBadRequest() throws IOException {
        MockMultipartFile csvDataCenters = null;
        InputStream fileEquipement = new FileInputStream(ResourceUtils.getFile("target/test-classes/equipementPhysique.csv"));
        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement);
        MockMultipartFile csvEquipementsVirtuels = null;
        MockMultipartFile csvApplications = null;
        MockMultipartFile csvMessagerie = null;
        MockMultipartFile csvEntite = null;

        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("test", "20230101", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));

        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
        assertEquals("La date du lot doit avoir le format yyyy-MM-dd", exception.getReason());
    }
}
