package org.mte.numecoeval.referentiel.infrastructure.adapter.export;

import org.apache.commons.csv.CSVPrinter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportMixElectriquePortImpl;
import org.mte.numecoeval.referentiel.factory.TestDataFactory;
import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.MixElectriqueRepository;

import java.io.IOException;
import java.io.StringWriter;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

class ImpactMixElectriqueCsvExportServiceTest {

    @InjectMocks
    MixElectriqueCsvExportService exportService;

    @Mock
    MixElectriqueRepository repository;

    @Mock
    CSVPrinter csvPrinter;

    @BeforeEach
    void setup() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void getHeadersShouldReturnSameHeadersAsImport() {
        Assertions.assertEquals(ImportMixElectriquePortImpl.getHeaders(), exportService.getHeaders());
    }

    @Test
    void getObjectsToWriteShouldReturnRepositoryFindAll() {
        var entities = List.of(
                TestDataFactory.MixElectriqueFactory.entity(
                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
                        "France", "FR",0.2, "Test"
                ),
                TestDataFactory.MixElectriqueFactory.entity(
                        TestDataFactory.CritereFactory.entity("Acidification", "",""),
                        "Angleterre", "EN",0.1, "Test"
                )
        );
        when(repository.findAll()).thenReturn(entities);

        assertEquals(entities, exportService.getObjectsToWrite());
    }

    @Test
    void printRecordShouldUseEntityAttributes() throws IOException {
        var entity = TestDataFactory.MixElectriqueFactory.entity(
                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
                "France", "FR",0.2, "Test"
        );
        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
        df.setMaximumFractionDigits(340);

        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));

        Mockito.verify(csvPrinter, times(1)).printRecord(
                entity.getPays(),
                entity.getRaccourcisAnglais(),
                entity.getCritere(),
                df.format(entity.getValeur()),
                entity.getSource());
    }

    @Test
    void logRecordErrorShouldLogSpecificErrorForRecord(){
        var entity = TestDataFactory.MixElectriqueFactory.entity(
                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
                "France", "FR",0.2, "Test"
        );

        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
    }

    @Test
    void logRecordErrorShouldLogGenericErrorForRecord(){
        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
    }

    @Test
    void logRecordErrorShouldLogGenericErrorForFile(){
        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
    }

    @Test
    void writeToCsvShouldReturnCSV() {
        // given
        var entities = List.of(
                TestDataFactory.MixElectriqueFactory.entity(
                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
                        "France", "FR",0.2, "Test"
                )
        );
        when(repository.findAll()).thenReturn(entities);
        StringWriter stringWriter = new StringWriter();

        // when
        exportService.writeToCsv(stringWriter);

        // Then
        String result = stringWriter.toString();
        assertEquals(
                "pays;raccourcisAnglais;critere;valeur;source\r\nFrance;FR;Changement climatique;0.2;Test\r\n",
                result
        );
    }
}
