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.ImportFacteurCaracterisationPortImpl;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.FacteurCaracterisationDTO;
import org.mte.numecoeval.referentiel.utils.Constants;
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.*;

public class ImportFacteurCaracterisationPortTest {
    ImportCSVReferentielPort<FacteurCaracterisationDTO> importPortToTest = new ImportFacteurCaracterisationPortImpl();

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

        assertEquals(4, resultatImport.getNbrLignesImportees());
        assertEquals(0, resultatImport.getErreurs().size());
        assertEquals(4, resultatImport.getObjects().size());
        String name = Constants.MIXELEC_NOM_LOW_VOLTAGE + "FR";
        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                        name.equals(dto.getNom())
                                && Constants.MIXELEC_ETAPEACV.equals(dto.getEtape())
                                && "Changement climatique".equals(dto.getCritere())
                                && Constants.MIXELEC_NIVEAU.equals(dto.getNiveau())
                                && Constants.MIXELEC_CATEGORIE.equals(dto.getCategorie())
                                && "France".equals(dto.getLocalisation())
                                && Double.valueOf(0.0813225).equals(dto.getValeur())
                                && "kWh".equals(dto.getUnite())
                                && "BaseImpact".equals(dto.getSource())
                                && "ADEO".equals(dto.getNomOrganisation())
                )
        );

        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                        "Laptop".equals(dto.getNom())
                                && "DISTRIBUTION".equals(dto.getEtape())
                                && "Ressources use, minerals and metals".equals(dto.getCritere())
                                && "HP".equals(dto.getDescription())
                                && Constants.EQUIPEMENT_NIVEAU.equals(dto.getNiveau())
                                && "End-user/Terminals".equals(dto.getTiers())
                                && "Consultation".equals(dto.getCategorie())
                                && "Allemagne".equals(dto.getLocalisation())
                                && Double.valueOf(0.000882).equals(dto.getValeur())
                                && "Item".equals(dto.getUnite())
                                && "NegaOctet".equals(dto.getSource())
                                && "ADEO".equals(dto.getNomOrganisation())
                )
        );

        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                        "Mobile network".equals(dto.getNom())
                                && "FABRICATION".equals(dto.getEtape())
                                && "Climate change".equals(dto.getCritere())
                                && Constants.RESEAU_NIVEAU.equals(dto.getNiveau())
                                && Constants.RESEAU_TIERS.equals(dto.getTiers())
                                && Double.valueOf(0.8).equals(dto.getConsoElecMoyenne())
                                && Double.valueOf(0.00000159).equals(dto.getValeur())
                                && "GB".equals(dto.getUnite())
                                && "NegaOctet".equals(dto.getSource())
                                && "ADEO".equals(dto.getNomOrganisation())
                )
        );
    }

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

        assertEquals(4, resultatImport.getNbrLignesImportees());
        assertEquals(3, resultatImport.getErreurs().size());
        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne nom ne peut être vide"::equals));
        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°5 est invalide : La colonne etapeacv ne peut être vide"::equals));
        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°6 est invalide : La colonne critere ne peut être vide"::equals));
        assertEquals(4, resultatImport.getObjects().size());
        String name = Constants.MIXELEC_NOM_LOW_VOLTAGE + "FR";
        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
                        name.equals(dto.getNom())
                                && Constants.MIXELEC_ETAPEACV.equals(dto.getEtape())
                                && "Changement climatique".equals(dto.getCritere())
                                && Constants.MIXELEC_NIVEAU.equals(dto.getNiveau())
                                && Constants.MIXELEC_CATEGORIE.equals(dto.getCategorie())
                                && "France".equals(dto.getLocalisation())
                                && Double.valueOf(0.0813225).equals(dto.getValeur())
                                && "kWh".equals(dto.getUnite())
                                && "BaseImpact".equals(dto.getSource())
                                && "ADEO".equals(dto.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));
    }

}
