package org.mte.numecoeval.referentiel.domain.port.input;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
import org.springframework.util.ResourceUtils;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import static org.mockito.Mockito.*;

class ImportCriterePortTest {

    ImportCSVReferentielPort<CritereDTO> importPortToTest = new ImportCriterePortImpl();

    @Test
    void importCSV_shouldImportAllDatas() throws Exception {
        File file = ResourceUtils.getFile("classpath:csv/unit/critere.csv");
        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));

        Assertions.assertEquals(5, resultatImport.getNbrLignesImportees());
        Assertions.assertEquals(0, resultatImport.getErreurs().size());
        Assertions.assertEquals(5, resultatImport.getObjects().size());
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Changement climatique".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "kg CO_{2} eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Émissions de particules fines".equals(dto.getNomCritere())
                        && "Émissions de particules fines".equals(dto.getDescription())
                        && "Diseaseincidence".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Radiations ionisantes".equals(dto.getNomCritere())
                        && "Description de Tests".equals(dto.getDescription())
                        && "kBq U-235 eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Acidification".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "mol H^{+} eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Épuisement des ressources naturelles (minérales et métaux)".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "kg Sb eq".equals(dto.getUnite()))
        );
    }

    @Test
    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
        File file = ResourceUtils.getFile("classpath:csv/unit/critere_errorInMiddle.csv");
        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));

        Assertions.assertEquals(5, resultatImport.getNbrLignesImportees());
        Assertions.assertEquals(1, resultatImport.getErreurs().size());
        Assertions.assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne nomCritere ne peut être vide"::equals));
        Assertions.assertEquals(5, resultatImport.getObjects().size());
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Changement climatique".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "kg CO_{2} eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Émissions de particules fines".equals(dto.getNomCritere())
                        && "Émissions de particules fines".equals(dto.getDescription())
                        && "Diseaseincidence".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Radiations ionisantes".equals(dto.getNomCritere())
                        && "Description de Tests".equals(dto.getDescription())
                        && "kBq U-235 eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Acidification".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "mol H^{+} eq".equals(dto.getUnite()))
        );
        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                "Épuisement des ressources naturelles (minérales et métaux)".equals(dto.getNomCritere())
                        && "".equals(dto.getDescription())
                        && "kg Sb eq".equals(dto.getUnite()))
        );
    }

    @Test
    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));

        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
        Assertions.assertEquals(1, resultatImport.getErreurs().size());
        Assertions.assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
    }

    @Test
    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
        DataInputStream dataInputStream = mock(DataInputStream.class);
        doNothing().when(dataInputStream).close();

        var resultatImport = importPortToTest.importCSV(dataInputStream);

        verify(dataInputStream).close();
        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
        Assertions.assertEquals(1, resultatImport.getErreurs().size());
        Assertions.assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
    }

    @Test
    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
        DataInputStream dataInputStream = mock(DataInputStream.class);
        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();

        var resultatImport = importPortToTest.importCSV(dataInputStream);

        verify(dataInputStream).close();
        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
        Assertions.assertEquals(1, resultatImport.getErreurs().size());
        Assertions.assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
    }
}
