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

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

import java.io.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;

class ImportTypeItemPortTest {

    ImportCSVReferentielPort<TypeItemDTO> importPortToTest = new ImportTypeItemPortImpl();

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

        assertEquals(2, resultatImport.getNbrLignesImportees());
        assertEquals(0, resultatImport.getErreurs().size());
        assertEquals(2, resultatImport.getObjects().size());
        assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO ->
                        "Serveur".equals(typeItemDTO.getType())
                                && typeItemDTO.getCategorie().isEmpty()
                                && typeItemDTO.isServeur()
                                && "Exemple de serveur basique".equals(typeItemDTO.getCommentaire())
                                && Double.valueOf(6.0).equals(typeItemDTO.getDureeVieDefaut())
                                && "NegaOctet".equals(typeItemDTO.getSource())
                                && "serveur_par_defaut".equals(typeItemDTO.getRefItemParDefaut())
                                && "ADEO".equals(typeItemDTO.getNomOrganisation())
                )
        );
        assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO ->
                        "deplacement voiture hybride".equals(typeItemDTO.getType())
                                && "deplacement_hybride".equals(typeItemDTO.getCategorie())
                                && !typeItemDTO.isServeur()
                                && "Exemple d'opération non it".equals(typeItemDTO.getCommentaire())
                                && Double.valueOf(50.0).equals(typeItemDTO.getDureeVieDefaut())
                                && "SSG".equals(typeItemDTO.getSource())
                                && "deplacement_voiture_hybride".equals(typeItemDTO.getRefItemParDefaut())
                                && "ADEO".equals(typeItemDTO.getNomOrganisation())
                )
        );
    }

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

        assertEquals(2, resultatImport.getNbrLignesImportees());
        assertEquals(1, resultatImport.getErreurs().size());
        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°3 est invalide : La colonne type ne peut être vide"::equals));
        assertEquals(2, resultatImport.getObjects().size());
        assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO ->
                        "Serveur".equals(typeItemDTO.getType())
                                && typeItemDTO.getCategorie().isEmpty()
                                && typeItemDTO.isServeur()
                                && "Exemple de serveur basique".equals(typeItemDTO.getCommentaire())
                                && Double.valueOf(6.0).equals(typeItemDTO.getDureeVieDefaut())
                                && "NegaOctet".equals(typeItemDTO.getSource())
                                && "serveur_par_defaut".equals(typeItemDTO.getRefItemParDefaut())
                                && "ADEO".equals(typeItemDTO.getNomOrganisation())
                )
        );
        assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO ->
                        "deplacement voiture hybride".equals(typeItemDTO.getType())
                                && "deplacement_hybride".equals(typeItemDTO.getCategorie())
                                && !typeItemDTO.isServeur()
                                && "Exemple d'opération non it".equals(typeItemDTO.getCommentaire())
                                && Double.valueOf(50.0).equals(typeItemDTO.getDureeVieDefaut())
                                && "SSG".equals(typeItemDTO.getSource())
                                && "deplacement_voiture_hybride".equals(typeItemDTO.getRefItemParDefaut())
                                && "ADEO".equals(typeItemDTO.getNomOrganisation())
                )
        );
    }

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

        assertEquals(0, resultatImport.getNbrLignesImportees());
        assertEquals(1, resultatImport.getErreurs().size());
        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, "ADEO");

        verify(dataInputStream).close();
        assertEquals(0, resultatImport.getNbrLignesImportees());
        assertEquals(1, resultatImport.getErreurs().size());
        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, "ADEO");

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