package org.mte.numecoeval.calculs.domain.service;

import org.junit.jupiter.api.Test;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
import org.mte.numecoeval.calculs.domain.data.entree.Messagerie;
import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactMessagerie;
import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielCritere;
import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactMessagerie;
import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactMessagerieService;
import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactMessagerieServiceImpl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;

import static org.junit.jupiter.api.Assertions.*;

class CalculImpactMessagerieServiceTest {

    CalculImpactMessagerieService calculImpactMessagerieService = new CalculImpactMessagerieServiceImpl();

    @Test
    void whenValidMessagerie_shoudCalculerImpactMessagerie() {
        //GIVEN
        var dateCalcul = LocalDateTime.now();
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        var referentielImpactMessagerie = ReferentielImpactMessagerie.builder()
                .critere(critere.getNomCritere())
                .source("Source RFT")
                .constanteOrdonneeOrigine(20d)
                .constanteCoefficientDirecteur(30d)
                .build();
        var messagerie = Messagerie.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .moisAnnee(202211)
                .nombreMailEmis(300d)
                .nombreMailEmisXDestinataires(900d)
                .volumeTotalMailEmis(5000d)
                .build();
        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
                .dateCalcul(dateCalcul)
                .critere(critere)
                .impactsMessagerie(Collections.singletonList(referentielImpactMessagerie))
                .messagerie(messagerie)
                .build();


        //WHEN
        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactMessagerie);
        assertEquals(468000d, impactMessagerie.getImpactMensuel());
        assertEquals("OK", impactMessagerie.getStatutIndicateur());
        assertEquals("{\"critere\":\"Changement Climatique\",\"volumeTotalMailEmis\":5000.0,\"nombreMailEmis\":300.0,\"constanteCoefficientDirecteur\":30.0,\"poidsMoyenMail\":16.666666666666668,\"constanteOrdonneeOrigine\":20.0,\"nombreMailEmisXDestinataires\":900.0,\"formule\":\"poidsMoyenMail(16.666666666666668) = volumeTotalMailEmis(5000.0)/nombreMailEmis(300.0);\\nimpactMensuel = (constanteCoefficientDirecteur (30.0) * poidsMoyenMail(16.666666666666668) + constanteOrdonneeOrigine(20.0)) * nombreMailEmisXDestinataires(900.0)\\n\"}", impactMessagerie.getTrace());
    }

    @Test
    void whenNonValidMessagerie_shouldReturnEmptyResult() {


        var dateCalcul = LocalDateTime.now();
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        var referentielImpactMessagerie = ReferentielImpactMessagerie.builder()
                .critere(critere.getNomCritere())
                .source("Source RFT")
                .constanteOrdonneeOrigine(20d)
                .constanteCoefficientDirecteur(30d)
                .build();
        var messagerie = Messagerie.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .moisAnnee(202211)
                .nombreMailEmis(0d)
                .nombreMailEmisXDestinataires(0d)
                .volumeTotalMailEmis(0d)
                .build();
        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
                .dateCalcul(dateCalcul)
                .critere(critere)
                .impactsMessagerie(Collections.singletonList(referentielImpactMessagerie))
                .messagerie(messagerie)
                .build();

        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);

        assertContentIndicateur(demandeCalcul, impactMessagerie);
        assertNull(impactMessagerie.getImpactMensuel());
        assertEquals("ERREUR", impactMessagerie.getStatutIndicateur());
        assertEquals("{\"erreur\":\"ErrCalcFonc : Calcul d'impact messagerie : Critère : Changement Climatique, Mois Années : 202211, nombreMailEmis 0.0=< 0.0\"}", impactMessagerie.getTrace());
    }

    @Test
    void whenReferentielIsNotFound_shouldReturnEmptyResult() {


        var dateCalcul = LocalDateTime.now();
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        var messagerie = Messagerie.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .moisAnnee(202211)
                .nombreMailEmis(0d)
                .nombreMailEmisXDestinataires(0d)
                .volumeTotalMailEmis(0d)
                .build();
        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
                .dateCalcul(dateCalcul)
                .critere(critere)
                .impactsMessagerie(Collections.emptyList())
                .messagerie(messagerie)
                .build();

        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);

        assertContentIndicateur(demandeCalcul, impactMessagerie);
        assertNull(impactMessagerie.getImpactMensuel());
        assertEquals("ERREUR", impactMessagerie.getStatutIndicateur());
        assertEquals("{\"erreur\":\"ErrCalcFonc : Référentiel ImpactMessagerie indisponible pour le critère Changement Climatique\"}", impactMessagerie.getTrace());
    }

    private static void assertContentIndicateur(DemandeCalculImpactMessagerie demandeCalcul, ImpactMessagerie impactMessagerie) {
        assertNotNull(impactMessagerie);
        assertEquals("1.0", impactMessagerie.getVersionCalcul());
        assertEquals(demandeCalcul.getDateCalcul(), impactMessagerie.getDateCalcul());
        assertEquals(demandeCalcul.getCritere().getNomCritere(), impactMessagerie.getCritere());
        assertEquals(demandeCalcul.getCritere().getUnite(), impactMessagerie.getUnite());
        assertEquals(demandeCalcul.getMessagerie().getMoisAnnee(), impactMessagerie.getMoisAnnee());
        assertEquals(demandeCalcul.getMessagerie().getNombreMailEmis(), impactMessagerie.getNombreMailEmis());
        assertEquals(demandeCalcul.getMessagerie().getVolumeTotalMailEmis(), impactMessagerie.getVolumeTotalMailEmis());
        assertEquals(demandeCalcul.getMessagerie().getNomLot(), impactMessagerie.getNomLot());
        assertEquals(demandeCalcul.getMessagerie().getDateLot(), impactMessagerie.getDateLot());
        assertEquals(demandeCalcul.getMessagerie().getNomEntite(), impactMessagerie.getNomEntite());
        assertEquals(demandeCalcul.getMessagerie().getNomOrganisation(), impactMessagerie.getNomOrganisation());
        assertEquals(demandeCalcul.getMessagerie().getNomSourceDonnee(), impactMessagerie.getNomSourceDonnee());
    }
}
