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

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementVirtuel;
import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementVirtuelService;
import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementVirtuelServiceImpl;
import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactVirtuelUtils;
import org.springframework.boot.test.system.OutputCaptureExtension;

import java.time.LocalDate;
import java.time.LocalDateTime;

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

@Slf4j
@ExtendWith({MockitoExtension.class, OutputCaptureExtension.class})
class CalculImpactEquipementVirtuelServiceTest {

    @Spy
    private ObjectMapper objectMapper;
    private CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService;

    @BeforeEach
    void setUp() {
        calculImpactEquipementVirtuelService = new CalculImpactEquipementVirtuelServiceImpl(objectMapper);
    }

    /**
     * CAF 1
     * Nombre total de vCPU renseigné
     * calculIndicateurImpactEquipementPhysique * EqV.vCPU / NbvCPU
     * Impact d’utilisation « VM1 »= 234,62784 x 7/19=86,442kgCO2eq
     */
    @Test
    void whenTypeEqvIsCalculAndTotalVCPUIsNotNull_shouldReturnCalculImpactUsingTotalVCPU() {

        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .vCPU(7)
                .typeEqv("calcul")
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .consoElecMoyenne(100.0d)
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(7 + 3 + 9)
                .build();
        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        assertNotNull(impactEquipementVirtuel);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(86.44183578947367d, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(36.8421052631579d, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) * equipementVirtuel.vCPU(7) / nbvCPU(19)\",\"nbEquipementsVirtuels\":3,\"nbTotalVCPU\":19}", impactEquipementVirtuel.getTrace());
    }


    /**
     * CAF3
     * Nombre total de vCPU renseigné non renseigné et Nombre de VM > 1
     * calculIndicateurImpactEquipementPhysique * 1 / NbVM
     * Impact d’utilisation « VM3 »=234,62784 x 1/3=78.209279999 kgCO2eq
     */
    @Test
    void whenTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(100.0d)
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(null)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(78.20927999999999, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(33.333333333333336, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel.getTrace());

    }

    /**
     * Taiga 457
     * Type d'équipement virtuel n'est pas "calcul" ET Nombre total de vCPU renseigné et Nombre de VM > 1
     * calculIndicateurImpactEquipementPhysique * 1 / NbVM
     * Impact d’utilisation « VM3 »=234,62784 x 1/3=78.209279999 kgCO2eq
     */
    @Test
    void whenTypeEqvIsNotCalculAndTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .typeEqv("notCalcul")
                .vCPU(7)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(100.0d)
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(7 + 3 + 9)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(78.20927999999999, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(33.333333333333336, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) / nbVM(3)\",\"nbEquipementsVirtuels\":3,\"nbTotalVCPU\":19}", impactEquipementVirtuel.getTrace());
    }

    /**
     * CAF4
     * Le nombre de VM est null et le nombre total de vCPU est null : le calcul est impossible et fini par une erreur Fonctionnelle.
     * Impact d'utilisation « VM4 »= ErrCalcFonc("certaines données sur l'équipement virtuel sont manquantes ou incorrectes")
     */
    @Test
    void whenTotalVCPUAndNbrVirtualEquipementAreNull_shouldReturnImpactError() {
        EquipementVirtuel equipementVirtuel = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel.getNomEquipementPhysique())
                .build();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(LocalDateTime.now())
                .equipementVirtuel(equipementVirtuel)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(null)
                .nbTotalVCPU(null)
                .build();

        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
        assertNull(impactEquipementVirtuel.getImpactUnitaire());
        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
        assertTrue(impactEquipementVirtuel.getTrace().contains("Certaines données sur l'équipement virtuel sont manquantes ou incorrectes"));
    }

    @Test
    void whenNbrVirtualEquipementIs0_shouldReturnImpactError() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(100.0d)
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(0)
                .nbTotalVCPU(null)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
        assertNull(impactEquipementVirtuel.getImpactUnitaire());
        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
        assertTrue(impactEquipementVirtuel.getTrace().contains("Certaines données sur l'équipement virtuel sont manquantes ou incorrectes"));
    }

    /**
     * Cas arrivé avec la V2.
     * Si l'impact unitaire de l'équipement physique est à un statut différent de OK, alors l'impact résultant est en erreur.
     */
    @Test
    void whenBaseImpactIsInError_shouldReturnImpactError() {

        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .vCPU(7)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(null)
                .unite("kgCO2eq")
                .consoElecMoyenne(null)
                .statutIndicateur("ERREUR")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(7 + 3 + 9)
                .build();
        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        assertNotNull(impactEquipementVirtuel);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertNull(impactEquipementVirtuel.getImpactUnitaire());
        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
        assertTrue(impactEquipementVirtuel.getTrace().contains("L'indicateur d'impact équipement associé est au statut : ERREUR"));
    }

    /**
     * Cas arrivé avec la V2.
     * Si l'impact unitaire de l'équipement physique est null, alors l'impact résultant est en erreur.
     */
    @Test
    void whenBaseImpactWithNullValues_shouldReturnImpactError() {

        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .vCPU(7)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(null)
                .unite("kgCO2eq")
                .consoElecMoyenne(null)
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();
        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(7 + 3 + 9)
                .build();
        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        assertNotNull(impactEquipementVirtuel);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertNull(impactEquipementVirtuel.getImpactUnitaire());
        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
        assertTrue(impactEquipementVirtuel.getTrace().contains("L'impact unitaire de l'équipement physique parent est null"));
    }


    /**
     * CAF5
     * Si ConsoElecMoyenne est null et impact unitaire OK, calcul impact OK
     */
    @Test
    void caf5() {

        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .vCPU(7)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(2)
                .nbTotalVCPU(null)
                .build();

        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(117.31392d, impactEquipementVirtuel.getImpactUnitaire());
        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
    }

    @Test
    void shouldGetTraceCalculVm() throws Exception {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("Vm1")
                .vCPU(7)
                .typeEqv("calcul")
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .impactUnitaire(234.62784d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(7+3+9)
                .build();
        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        var formule = TraceCalculImpactVirtuelUtils.getFormuleWithTotalVCPU(demandeCalcul);
        var expected = objectMapper.writeValueAsString(TraceCalculImpactEquipementVirtuel.builder()
                .nbTotalVCPU(demandeCalcul.getNbTotalVCPU())
                .nbEquipementsVirtuels(demandeCalcul.getNbEquipementsVirtuels())
                .formule(formule)
                .build());

        assertEquals(expected, impactEquipementVirtuel.getTrace());
    }

    /*
    Taiga 437
     */
    @Test
    void forTaiga437VM1_shouldReturnCalculImpactUsingProrataFormula() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("VM1")
                .typeEqv("calcul")
                .vCPU(8)
                .capaciteStockage(5.0)
                .cleRepartition(0.2)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(2840.d)
                .impactUnitaire(2840.d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(10)
                .nbTotalVCPU(null)
                .stockageTotalVirtuel(null)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(568.0, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(568.0, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.cleRepartition(0.2)\"}", impactEquipementVirtuel.getTrace());
    }

    @Test
    void forTaiga437VM2_shouldReturnCalculImpactUsingProrataOnCPUFormula() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("VM2")
                .typeEqv("calcul")
                .vCPU(8)
                .capaciteStockage(null)
                .cleRepartition(null)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(2840.d)
                .impactUnitaire(2840.d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(10)
                .nbTotalVCPU(16)
                .stockageTotalVirtuel(null)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(1420.0, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(1420.0, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.vCPU(8) / nbvCPU(16)\",\"nbEquipementsVirtuels\":10,\"nbTotalVCPU\":16}", impactEquipementVirtuel.getTrace());
    }

    /*
    Calcul au prorata du nombre d'équipement
     */
    @Test
    void forTaiga437VM4_shouldReturnCalculImpactUsingProrataFormula() {
        //GIVEN
        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("VM4")
                .typeEqv("calcul")
                .vCPU(null)
                .capaciteStockage(5.0)
                .cleRepartition(null)
                .build();
        EquipementVirtuel equipementVirtuel2 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("VM5")
                .typeEqv("calcul")
                .vCPU(null)
                .capaciteStockage(10.0)
                .cleRepartition(null)
                .build();
        EquipementVirtuel equipementVirtuel3 = EquipementVirtuel.builder()
                .dateLot(LocalDate.of(2022,1,1))
                .nomOrganisation("Test")
                .nomLot("Test|20220101")
                .nomSourceDonnee("Source_Test")
                .nomEquipementPhysique("equipement1")
                .nomEquipementVirtuel("VM5")
                .typeEqv("calcul")
                .vCPU(null)
                .capaciteStockage(30.0)
                .cleRepartition(null)
                .build();
        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
                .etapeACV("UTILISATION")
                .critere("Changement climatique")
                .typeEquipement("Serveur")
                .consoElecMoyenne(2840.d)
                .impactUnitaire(2840.d)
                .unite("kgCO2eq")
                .statutIndicateur("OK")
                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
                .build();
        LocalDateTime dateCalcul = LocalDateTime.now();

        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel1)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(null)
                .stockageTotalVirtuel(null)
                .build();

        DemandeCalculImpactEquipementVirtuel demandeCalcul2 = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel2)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(null)
                .stockageTotalVirtuel(null)
                .build();

        DemandeCalculImpactEquipementVirtuel demandeCalcul3 = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(dateCalcul)
                .equipementVirtuel(equipementVirtuel3)
                .impactEquipement(impactEquipementPhysique)
                .nbEquipementsVirtuels(3)
                .nbTotalVCPU(null)
                .stockageTotalVirtuel(null)
                .build();

        //WHEN
        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
        var impactEquipementVirtuel2 = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul2);
        var impactEquipementVirtuel3 = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul3);

        //THEN
        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
        assertContentIndicateur(demandeCalcul2, impactEquipementVirtuel2);
        assertContentIndicateur(demandeCalcul3, impactEquipementVirtuel3);
        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
        assertEquals(946.6666666666666, impactEquipementVirtuel.getImpactUnitaire());
        assertEquals(946.6666666666666, impactEquipementVirtuel.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel.getTrace());
        assertEquals("OK", impactEquipementVirtuel2.getStatutIndicateur());
        assertEquals(946.6666666666666, impactEquipementVirtuel2.getImpactUnitaire());
        assertEquals(946.6666666666666, impactEquipementVirtuel2.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel2.getTrace());
        assertEquals("OK", impactEquipementVirtuel3.getStatutIndicateur());
        assertEquals(946.6666666666666, impactEquipementVirtuel3.getImpactUnitaire());
        assertEquals(946.6666666666666, impactEquipementVirtuel3.getConsoElecMoyenne());
        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel3.getTrace());
    }


    private void assertContentIndicateur(DemandeCalculImpactEquipementVirtuel source, ImpactEquipementVirtuel result) {
        assertNotNull(result);
        assertEquals(source.getEquipementVirtuel().getNomEquipementPhysique(), result.getNomEquipement());
        assertEquals(source.getEquipementVirtuel().getNomEquipementVirtuel(), result.getNomEquipementVirtuel());

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

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

        assertEquals(source.getImpactEquipement().getCritere(), result.getCritere());
        assertEquals(source.getImpactEquipement().getEtapeACV(), result.getEtapeACV());
        assertEquals(source.getImpactEquipement().getUnite(), result.getUnite());

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