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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.demande.OptionsCalcul;
import org.mte.numecoeval.calculs.domain.data.entree.DataCenter;
import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.referentiel.*;
import org.mte.numecoeval.calculs.domain.data.trace.ConsoElecAnMoyenne;
import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
import org.mte.numecoeval.calculs.domain.data.trace.MixElectrique;
import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementPhysiqueService;
import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementPhysiqueServiceImpl;
import org.mte.numecoeval.calculs.domain.port.input.service.impl.DureeDeVieEquipementPhysiqueServiceImpl;
import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactEquipementPhysiqueUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Collections;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;


@ExtendWith(MockitoExtension.class)
class CalculImpactEquipementPhysiqueServiceTest {

    private CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService;
    private String etapeACV;
    private ReferentielCritere critere;
    private LocalDateTime dateCalcul;
    private String refEquipementCible;
    private String refEquipementParDefaut;
    private EquipementPhysique equipementPhysique;
    private ReferentielImpactEquipement referentielImpactEquipement;
    private ReferentielMixElectrique referentielMixElectrique;
    ReferentielCorrespondanceRefEquipement refEquipement;
    ReferentielTypeEquipement typeEquipement;
    ReferentielHypothese referentielHypothese;
    @Mock
    private DureeDeVieEquipementPhysiqueServiceImpl dureeDeVieEquipementPhysiqueService;

    @BeforeEach
    public void init() throws Exception {
        MockitoAnnotations.openMocks(this);
        calculImpactEquipementPhysiqueService = new CalculImpactEquipementPhysiqueServiceImpl(
                dureeDeVieEquipementPhysiqueService
        );
        etapeACV = "UTILISATION";
        String etapeACV = "UTILISATION";
        critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        dateCalcul = LocalDateTime.now();
        refEquipementCible = "Apple Iphone 11";
        refEquipementParDefaut = "Apple Iphone 11";
        equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("COPE")
                .build();
        referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF1")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(refEquipementCible)
                .consoElecMoyenne(0.09)
                .build();
        referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF1() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Apple Iphone 11";
        String refEquipementParDefaut = "Apple Iphone 11";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                // Consommation electrique annuelle à null, celle du référentiel sera utilisé
                .consoElecAnnuelle(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF1")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(refEquipementCible)
                .consoElecMoyenne(0.09)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.0073, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    /* même cas que le CAF1 mais avec une consoElecAnnuelle à 0 au lieu de null.
     * Conformément au Taiga 895 : le 0 est bien appliqué et ramène le résultat à 0
     */
    @Test
    void taiga895_shouldApplyConsoElecAnnuelWithConsoElecAnnuelleAt0_CAF1() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Apple Iphone 11";
        String refEquipementParDefaut = "Apple Iphone 11";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                // Consommation electrique annuelle à 0, elle sera utilisé et rend le calcul à 0
                .consoElecAnnuelle(0.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF1")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(0.09)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0, actualImpactUnitaireLimited);
        assertEquals(0, actual.getConsoElecMoyenne());
        assertNotEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF2_neededCorrection() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Ecran2";
        String refEquipementParDefaut = "Ecran2";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran2")
                .modele("Ecran2")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(30.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF2")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(70.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(3, RoundingMode.DOWN).doubleValue();
        assertEquals(5.692, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF3_decimalFixing() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "OrdinateurBureau3";
        String refEquipementParDefaut = "OrdinateurBureau3";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("OrdinateurBureau")
                .nomEquipementPhysique("OrdinateurBureau3")
                .modele("OrdinateurBureau3")
                .paysDUtilisation("Irlande")
                .nomCourtDatacenter(null)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF3")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(3504.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("Irlande")
                .raccourcisAnglais("IR")
                .source("CAF3")
                .valeur(0.648118)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        assertEquals(dateCalcul, actual.getDateCalcul());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        // quantité * refEquipementPhysique.consoElecMoyenne * MixElec
        assertEquals(BigDecimal.valueOf(1.0 * 3504.0 * 0.648118).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void taiga918_DataCenterReferencedAndUsedForPUE_CAF1() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia2")
                .nomLongDatacenter("sequoia2")
                .localisation("France")
                .pue(1.43)
                .build();
        String refEquipementCible = "ref-Serveur1";
        String refEquipementParDefaut = "ref-Serveur1";
        LocalDateTime dateCalcul = LocalDateTime.now();
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_100")
                .dateAchat(LocalDate.of(2018, 10, 1))
                .modele("ref-Serveur1")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia2")
                .dataCenter(dataCenter)
                .quantite(2.0)
                .consoElecAnnuelle(500.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.08)
                .build();

        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        assertEquals(dateCalcul, actual.getDateCalcul());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        // quantité * equipementPhysique.consoElecAnnuelle * DataCenter.pue * MixElec(France)
        assertEquals(BigDecimal.valueOf(2.0 * 500.0 * 1.43 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
    }

    @Test
    void taiga918_DataCenterWithoutPUEAndDefaultPUEUsed_CAF2() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia3")
                .nomLongDatacenter("sequoia3")
                .localisation("France")
                .pue(null)
                .build();
        String refEquipementCible = "ref-Serveur4";
        String refEquipementParDefaut = "ref-Serveur4";
        LocalDateTime dateCalcul = LocalDateTime.now();
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_104")
                .modele("ref-Serveur4")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia3")
                .dataCenter(dataCenter)
                .consoElecAnnuelle(500.0)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(2.0)
                .code("PUEParDefaut")
                .source("CAF2")
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF2")
                .valeur(0.08)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        assertEquals(dateCalcul, actual.getDateCalcul());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        // quantité * equipementPhysique.consoElecAnnuelle * ref_Hypothese(PUEParDefaut).valeur * MixElec France
        assertEquals(BigDecimal.valueOf(1.0 * 500.0 * 2.0 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
    }

    @Test
    void taiga918_ConsoElecMoyenneUsedFromRef_CAF3() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia2")
                .nomLongDatacenter("sequoia2")
                .localisation("France")
                .pue(1.43)
                .build();
        String refEquipementCible = "ref-Serveur2";
        String refEquipementParDefaut = "ref-Serveur2";
        LocalDateTime dateCalcul = LocalDateTime.now();
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_101")
                .modele("ref-Serveur2")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia2")
                .dataCenter(dataCenter)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF2")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(10512.0)
                .valeur(1139.839200000007)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF3")
                .valeur(0.08)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        assertEquals(dateCalcul, actual.getDateCalcul());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        // quantité * refEquipementPhysique.consoElecMoyenne * DataCEnter.pue * MixElec France
        assertEquals(BigDecimal.valueOf(1.0 * 10512.0 * 1.43 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void taiga918_CAF4_whenDonneesConsoElecAbsente_shouldReturnErreurCalcul() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia2")
                .nomLongDatacenter("sequoia2")
                .localisation("France")
                .pue(1.43)
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "ref-Serveur3";
        String refEquipementParDefaut = "ref-Serveur3";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_103")
                .modele("ref-Serveur3")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia2")
                .dataCenter(dataCenter)
                .consoElecAnnuelle(null)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF4")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(null)
                .valeur(1139.839200000007)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Donnée de consommation electrique manquante : equipementPhysique : Serveur_103, RefEquipementCible : ref-Serveur3, RefEquipementParDefaut : ref-Serveur3\"}",
                actual.getTrace()
        );
    }

    @Test
    void taiga918_ecranCAF5() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "ref-Ecran";
        String refEquipementParDefaut = "ref-Ecran";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran_1")
                .modele("ref-Ecran")
                .paysDUtilisation("France")
                .serveur(false)
                .nomCourtDatacenter(null)
                .dataCenter(null)
                .quantite(1.0)
                .consoElecAnnuelle(100.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF5")
                .valeur(0.08)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        assertEquals(dateCalcul, actual.getDateCalcul());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        // quantité * equipementPhysique.consoElecAnnuelle * MixElec France
        assertEquals(BigDecimal.valueOf(1.0 * 100.0 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF4() throws Exception {

        //Given
        String etapeACV = "FABRICATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Ordinateur4";
        String refEquipementParDefaut = "Ordinateur4";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Desktop")
                .nomEquipementPhysique("Ordinateur4")
                .modele("Ordinateur4")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF4")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(null)
                .valeur(142.0)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();

        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(5.0d).build());

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(28.4, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF5() throws Exception {

        //Given
        String etapeACV = "FIN_DE_VIE";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "KyoceraTaskalfa3253Ci";
        String refEquipementParDefaut = "KyoceraTaskalfa3253Ci";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Imprimante")
                .nomEquipementPhysique("Imprimante5")
                .modele("KyoceraTaskalfa3253Ci")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF5")
                .etape(etapeACV)
                .critere(critere.getNomCritere())
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(123.3)
                .valeur(17.3)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();
        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(6.0).build());

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(2.8833, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_CAF6() throws Exception {

        //Given
        String etapeACV = "DISTRIBUTION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Ecran6";
        String refEquipementParDefaut = "Ecran6";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran6")
                .modele("Ecran6")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF6")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(123.3)
                .valeur(1.273)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();
        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(7.0).build());

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.1818, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void shouldCalculerImpactEquipementPhysique_whenEtapeACVUTILISATIONAndEquipementConsoElecMoyenneFilled() throws Exception {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Apple Iphone 11";
        String refEquipementParDefaut = "Apple Iphone 11";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .consoElecAnnuelle(0.09)
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.0073, actualImpactUnitaireLimited);
        assertEquals(equipementPhysique.getConsoElecAnnuelle(), actual.getConsoElecMoyenne());
    }

    @Test
    void shouldBuildTraceWithFirstFormulaScenario1() throws JsonProcessingException {

        //GIVEN
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
        String refEquipementCible = "Samsung SMP";
        String refEquipementParDefaut = "Samsung SMP";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("Samsung S21")
                .modele("Samsung SMP")
                .consoElecAnnuelle(200d)
                .paysDUtilisation("France")
                .nbJourUtiliseAn(230d)
                .serveur(false)
                .quantite(3d)
                .build();

        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("Source-Mix")
                .valeur(150d)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(LocalDateTime.now())
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormulePremierScenario(3d, 200d, 150d, 1.0);

        var consoElecAnMoyenne = ConsoElecAnMoyenne.builder().valeurItemConsoElecAnnuelle(200d).valeur(200d).build();
        var mixElectrique = MixElectrique.builder().valeur(150d).valeurReferentielMixElectrique(150d).sourceReferentielMixElectrique("Source-Mix").build();
        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
                .formule(formule)
                .consoElecAnMoyenne(consoElecAnMoyenne)
                .mixElectrique(mixElectrique)
                .build();
        var expected = new ObjectMapper().writeValueAsString(trace);
        //WHEN
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);
        //THEN
        assertEquals(expected, actual.getTrace());
    }

    @Test
    void shouldBuildTraceWithFirstFormulaScenario2() throws JsonProcessingException {
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
        DataCenter dataCenter = DataCenter.builder()
                .localisation("Spain")
                .pue(5d)
                .build();
        String refEquipementCible = "IBM E1080";
        String refEquipementParDefaut = "IBM E1080";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .quantite(6d)
                .modele("IBM E1080")
                .serveur(true)
                .dataCenter(dataCenter)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement("IBM E1080")
                .source("source-RefEquipement")
                .consoElecMoyenne(130d)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("Spain")
                .source("Source-Mix")
                .valeur(25d)
                .build();

        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(LocalDateTime.now())
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormulePremierScenario(6d, 130d, 5d * 25d, 1.0);

        var consoElecAnMoyenne = ConsoElecAnMoyenne.builder()
                .valeur(130d)
                .valeurReferentielConsoElecMoyenne(130d)
                .sourceReferentielFacteurCaracterisation("source-RefEquipement")
                .build();
        var mixElectrique = MixElectrique.builder()
                .valeur(125d)
                .dataCenterPue(5d)
                .valeurReferentielMixElectrique(25d)
                .sourceReferentielMixElectrique("Source-Mix")
                .isServeur(true)
                .build();
        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
                .formule(formule)
                .consoElecAnMoyenne(consoElecAnMoyenne)
                .mixElectrique(mixElectrique)
                .build();
        var expected = new ObjectMapper().writeValueAsString(trace);
        //WHEN
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);
        //THEN
        assertEquals(expected, actual.getTrace());
    }

    @Test
    void shouldBuildTraceWithSecondFormula() throws JsonProcessingException, CalculImpactException {
        String etapeACV = "Fin de vie";
        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
        LocalDate dateAchat = LocalDate.of(2020, 1, 22);
        LocalDate dateRetrait = LocalDate.of(2021, 5, 12);
        double quantite = 6d;
        double tauxUtilisation = 1.0;
        String refEquipementCible = "IBM E1080";
        String refEquipementParDefaut = "IBM E1080";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .quantite(quantite)
                .modele("IBM E1080")
                .dateAchat(dateAchat)
                .dateRetrait(dateRetrait)
                .serveur(false)
                .build();
        double valeurRefrentiel = 100d;
        String sourceReferentielImpactEquipement = "source-RefEquipement";
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement("IBM E1080")
                .source(sourceReferentielImpactEquipement)
                .consoElecMoyenne(130d)
                .valeur(valeurRefrentiel)
                .build();


        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(LocalDateTime.now())
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();


        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul)).thenCallRealMethod();

        var valeurDureeVie = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d;
        DureeDeVie dureeDeVie = DureeDeVie.builder()
                .valeurRetenue(valeurDureeVie)
                .methodeDureeUsage("REEL")
                .dureeUsageAmont(0.0)
                .dureeUsageAval(0.0)
                .dateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE))
                .dateRetrait(dateRetrait.format(DateTimeFormatter.ISO_DATE))
                .build();

        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormuleSecondScenario(quantite, valeurRefrentiel, valeurDureeVie, tauxUtilisation);

        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
                .formule(formule)
                .dureeDeVie(dureeDeVie)
                .valeurReferentielImpactEquipement(valeurRefrentiel)
                .sourceReferentielImpactEquipement(sourceReferentielImpactEquipement)
                .build();
        var expected = new ObjectMapper().writeValueAsString(trace);
        //WHEN
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);

        //THEN
        assertEquals(expected, actual.getTrace());
    }

    @Test
    void taiga862_CAF1_calculImpactEquipementPhysiqueWithoutCorrespondanceShouldUseRefEquipementParDefaut() throws Exception {

        //Given
        String etapeACV = "DISTRIBUTION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementParDefaut = "EcranParDefaut";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran6")
                .modele("Ecran6")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .source("CAF6")
                .refEquipement(refEquipementParDefaut)
                .consoElecMoyenne(123.3)
                .valeur(1.273)
                .build();

        ReferentielCorrespondanceRefEquipement refEquipement = null;
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();

        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(7.0).build());

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.1818, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void taiga862_CAF1_calculImpactEquipementPhysiqueWithoutImpactForCorrespondanceShouldUseRefEquipementParDefaut() throws Exception {

        //Given
        String etapeACV = "DISTRIBUTION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementParDefaut = "EcranParDefaut";
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .source("CAF6")
                .refEquipement(refEquipementParDefaut)
                .consoElecMoyenne(123.3)
                .valeur(1.273)
                .build();
        String refEquipementCible = "Ecran6";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran6")
                .modele("Ecran6")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();

        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();

        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(7.0).build());

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.1818, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void tech_whenDureeDeVieUnknown_shouldReturnIndicateurWithError() {

        //Given
        String etapeACV = "FIN_DE_VIE";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia2")
                .nomLongDatacenter("sequoia2")
                .localisation("France")
                .pue(1.43)
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "ref-Serveur3";
        String refEquipementParDefaut = "ref-Serveur3";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_103")
                .modele("ref-Serveur3")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia2")
                .dataCenter(dataCenter)
                .consoElecAnnuelle(null)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF4")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(100.0)
                .valeur(1139.839200000007)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Durée de vie de l'équipement inconnue\"}",
                actual.getTrace()
        );
    }

    @Test
    void verifyErrorWhenCallConsoElecAnMoyenneWithoutConsoInEntryWithImpactRefWithoutConso() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Apple Iphone 11";
        String refEquipementParDefaut = "Apple Iphone 11";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF5")
                .valeur(0.08)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF4")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(null)
                .valeur(1139.839200000007)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Donnée de consommation electrique manquante : equipementPhysique : Apple Iphone 11, RefEquipementCible : Apple Iphone 11, RefEquipementParDefaut : Apple Iphone 11\"}",
                actual.getTrace()
        );
    }

    @Test
    void verifyErrorWhenCallConsoElecAnMoyenneWithoutConsoInEntryAndNoImpactRef() {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementParDefaut = "EcranParDefaut";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Ecran")
                .nomEquipementPhysique("Ecran6")
                .modele("Ecran6")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Référentiel Impact Equipement inconnu\"}",
                actual.getTrace()
        );
    }

    @Test
    void tech_whenNoReferentielImpactEquipement_shouldReturnIndicateurWithError() throws CalculImpactException {
        //Given
        String etapeACV = "FIN_DE_VIE";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        DataCenter dataCenter = DataCenter.builder()
                .nomCourtDatacenter("sequoia2")
                .nomLongDatacenter("sequoia2")
                .localisation("France")
                .pue(1.43)
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "ref-Serveur3";
        String refEquipementParDefaut = "ref-Serveur3";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Serveur_103")
                .modele("ref-Serveur3")
                .paysDUtilisation("France")
                .serveur(true)
                .nomCourtDatacenter("sequoia2")
                .dataCenter(dataCenter)
                .consoElecAnnuelle(null)
                .quantite(1.0)
                .nbJourUtiliseAn(365.0)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(6.0)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.emptyList())
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Référentiel Impact Equipement inconnu\"}",
                actual.getTrace()
        );
    }

    @Test
    void tech_whenMixElectriqueNotFound_shouldReturnIndicateurWithError() throws Exception {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Apple Iphone 11";
        String refEquipementParDefaut = "Apple Iphone 11";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .consoElecAnnuelle(0.09)
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.emptyList())
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Il n'existe pas de Mix électrique pour cet équipement : critere: Changement Climatique - equipement: Apple Iphone 11 - Pays d'utilisation: France - NomCourtDatacenter: null\"}",
                actual.getTrace()
        );
    }

    @Test
    void tech_whenMixElectriqueNotFoundWithDataCenter_shouldReturnIndicateurWithError() throws Exception {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "IBM X96";
        String refEquipementParDefaut = "IBM X96";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("IBM X96")
                .modele("IBM X96")
                .paysDUtilisation("France")
                .consoElecAnnuelle(0.09)
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .nomCourtDatacenter("TanaMana 2")
                .dataCenter(
                        DataCenter.builder()
                                .nomCourtDatacenter("TanaMana 2")
                                .nomLongDatacenter("TanaMana 2 - Rack B")
                                .localisation("France")
                                .pue(6.2)
                                .build()
                )
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.emptyList())
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Il n'existe pas de Mix électrique pour cet équipement : critere: Changement Climatique - equipement: IBM X96 - Pays d'utilisation: France - NomCourtDatacenter: TanaMana 2\"}",
                actual.getTrace()
        );
    }

    @Test
    void tech_whenPUEUknown_shouldReturnIndicateurWithError() throws Exception {

        //Given
        String etapeACV = "UTILISATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "IBM X96";
        String refEquipementParDefaut = "IBM X96";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Serveur")
                .nomEquipementPhysique("Tanabana2-IBM X96")
                .modele("IBM X96")
                .paysDUtilisation("France")
                .consoElecAnnuelle(0.09)
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .nomCourtDatacenter("TanaMana 2")
                .dataCenter(
                        DataCenter.builder()
                                .nomCourtDatacenter("TanaMana 2")
                                .nomLongDatacenter("TanaMana 2 - Rack B")
                                .localisation("France")
                                .pue(null)
                                .build()
                )
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
                .critere(critere.getNomCritere())
                .pays("France")
                .raccourcisAnglais("FR")
                .source("CAF1")
                .valeur(0.0813225)
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();

        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );

        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertNull(actual.getImpactUnitaire());
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals(
                "{\"erreur\":\"ErrCalcFonc : Le PUE est manquant et ne permet le calcul de l'impact à l'usage de l'équipement : equipement: Tanabana2-IBM X96 - RefEquipementCible: IBM X96 - refEquipementParDefaut: IBM X96 - NomCourtDatacenter: TanaMana 2\"}",
                actual.getTrace()
        );
    }

    private void assertContentIndicateur(DemandeCalculImpactEquipementPhysique source, ImpactEquipementPhysique result) {
        assertNotNull(result);
        assertEquals(source.getEquipementPhysique().getNomEquipementPhysique(), result.getNomEquipement());
        assertEquals(source.getEquipementPhysique().getType(), result.getTypeEquipement());
        assertEquals(source.getEquipementPhysique().getStatut(), result.getStatutEquipementPhysique());
        assertEquals(source.getEquipementPhysique().getQuantite(), result.getQuantite());

        assertEquals(source.getEquipementPhysique().getNomLot(), result.getNomLot());
        assertEquals(source.getEquipementPhysique().getDateLot(), result.getDateLot());
        assertEquals(source.getEquipementPhysique().getNomOrganisation(), result.getNomOrganisation());
        assertEquals(source.getEquipementPhysique().getNomEntite(), result.getNomEntite());
        assertEquals(source.getEquipementPhysique().getNomSourceDonnee(), result.getNomSourceDonnee());

        assertEquals(source.getDateCalcul(), result.getDateCalcul());

        assertEquals(source.getCritere().getNomCritere(), result.getCritere());
        assertEquals(source.getEtape().getCode(), result.getEtapeACV());
        assertEquals(source.getCritere().getUnite(), result.getUnite());

        assertEquals("1.0", result.getVersionCalcul());
    }

    @Test
    void verifyFormulaForModeUtilisationCOPE() {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("COPE")
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.8)
                .code("taux_utilisation_COPE")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.0058, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void verifyFormulaForModeUtilisationBYOD() {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("BYOD")
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.57)
                .code("taux_utilisation_BYOD")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.0041, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void verifyFormulaForModeUtilisationModeUtilisationNull() {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.57)
                .code("taux_utilisation_BYOD")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(0.0073, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }

    @Test
    void verifyFormulaForModeUtilisationModeUtilisationUnknown() {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("COB")
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.57)
                .code("taux_utilisation_BYOD")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals("""
                {"erreur":"ErrCalcFonc : Le mode d'utilisation doit avoir les valeurs BYOD"}
                """.trim(), actual.getTrace());
    }

    @Test
    void verifyFormulaForModeUtilisationModeUtilisationCOPEButNotInRefHypotheses() {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("COPE")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("ERREUR", actual.getStatutIndicateur());
        assertEquals("""
                {"erreur":"ErrCalcFonc : Il n'y a pas d'hypotheses pour le taux d'utilisation"}
                """.trim(), actual.getTrace());
    }

    @Test
    void verifyFormulaForNotTUILISATIONModeUtilisationCOPE() throws Exception {
        //Given
        String etapeACV = "FABRICATION";
        ReferentielCritere critere = ReferentielCritere.builder()
                .nomCritere("Changement Climatique")
                .unite("kg CO_{2} eq")
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        String refEquipementCible = "Ordinateur4";
        String refEquipementParDefaut = "Ordinateur4";
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Desktop")
                .nomEquipementPhysique("Ordinateur4")
                .modele("Ordinateur4")
                .paysDUtilisation("France")
                .quantite(1.0)
                .modeUtilisation("COPE")
                .nbJourUtiliseAn(null)
                .build();
        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
                .source("CAF4")
                .critere(critere.getNomCritere())
                .etape(etapeACV)
                .refEquipement(equipementPhysique.getModele())
                .consoElecMoyenne(null)
                .valeur(142.0)
                .build();
        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
                .refEquipementCible(refEquipementCible)
                .modeleEquipementSource(equipementPhysique.getModele())
                .build();
        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
                .type(equipementPhysique.getType())
                .refEquipementParDefaut(refEquipementParDefaut)
                .dureeVieDefaut(null)
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.85)
                .code("taux_utilisation_COPE")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .hypotheses(Collections.singletonList(referentielHypothese))
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .optionsCalcul(new OptionsCalcul("REEL"))
                .build();
        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeurRetenue(5.0d).build());
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertEquals(dateCalcul, actual.getDateCalcul());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
        assertEquals(24.14, actualImpactUnitaireLimited);
        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
        assertNull(actual.getConsoElecMoyenne());
    }

    @Test
    void verifyFormulaForUTILISATIONTauxUtilisationFilled() throws Exception {
        //Given
        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
                .dateLot(LocalDate.of(2022, 1, 1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .type("Téléphone")
                .nomEquipementPhysique("Apple Iphone 11")
                .modele("Apple Iphone 11")
                .paysDUtilisation("France")
                .quantite(1.0)
                .nbJourUtiliseAn(216.0)
                .consoElecAnnuelle(0.09)
                .modeUtilisation("")
                .tauxUtilisation(0.1)
                .build();
        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
                .valeur(0.57)
                .code("taux_utilisation_BYOD")
                .source("RCP_SI")
                .build();
        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
                .builder()
                .dateCalcul(dateCalcul)
                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
                .critere(critere)
                .equipementPhysique(equipementPhysique)
                .correspondanceRefEquipement(refEquipement)
                .typeEquipement(typeEquipement)
                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
                .mixElectriques(Collections.singletonList(referentielMixElectrique))
                .hypotheses(Collections.singletonList(referentielHypothese))
                .build();
        //When
        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
                demandeCalcul
        );
        //Then
        assertContentIndicateur(demandeCalcul, actual);
        assertEquals("OK", actual.getStatutIndicateur());
        assertNotNull(actual.getImpactUnitaire());
        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(5, RoundingMode.DOWN).doubleValue();
        assertEquals(0.00073, actualImpactUnitaireLimited);
        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
    }
}