package org.mte.numecoeval.calculs.infrastructure.service.calcul;

import lombok.AllArgsConstructor;
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.port.input.service.CalculImpactEquipementVirtuelService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;


@Service
@AllArgsConstructor
public class CalculEquipementVirtuelService {

    CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService;


    /**
     * Calcule les impacts d'un equipement virtuel
     * Returne la liste d'impacts à partir des impacts de son equipement physique
     *
     * @param impactEquipementPhysiqueList la liste d'impact de l'equipement physique
     * @param equipementVirtuel            l'equipement virtuel
     * @param nbEquipementsVirtuels        nombre d'equipement virtuels lies a l'equipement physique
     * @param nbTotalVCPU                  nombre total de vcpu de l'equipement physique
     * @param stockageTotalVirtuel         stockage total
     * @return la liste d'impacts
     */
    public List<ImpactEquipementVirtuel> calculImpactEquipementVirtuel(
            List<ImpactEquipementPhysique> impactEquipementPhysiqueList,
            EquipementVirtuel equipementVirtuel,
            Integer nbEquipementsVirtuels,
            Integer nbTotalVCPU,
            Double stockageTotalVirtuel) {

        if (impactEquipementPhysiqueList.isEmpty()) return new ArrayList<>();

        LocalDateTime dateCalcul = LocalDateTime.now();

        return impactEquipementPhysiqueList.stream()
                .map(impact -> calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(
                        DemandeCalculImpactEquipementVirtuel.builder()
                                .dateCalcul(dateCalcul)
                                .equipementVirtuel(equipementVirtuel)
                                .nbEquipementsVirtuels(nbEquipementsVirtuels)
                                .nbTotalVCPU(nbTotalVCPU)
                                .stockageTotalVirtuel(stockageTotalVirtuel)
                                .impactEquipement(impact)
                                .build()))
                .toList();
    }

    /**
     * Calcule le totalVCPU d'une liste d'équipements virtuels
     * Somme le champs VCPU
     *
     * @param equipementVirtuelList la liste d'equipements virtuels
     * @return le total de VCPU
     */
    public Integer getTotalVCPU(List<EquipementVirtuel> equipementVirtuelList) {
        Integer totalVCPU = null;
        if (equipementVirtuelList.stream().noneMatch(vm -> vm.getVCPU() == null || vm.getVCPU() == 0)) {
            totalVCPU = equipementVirtuelList.stream().mapToInt(EquipementVirtuel::getVCPU).sum();
        }

        return totalVCPU;
    }

    /**
     * Calcule le totalStockage d'une liste d'équipements virtuels
     * Somme le champs capaciteStockage
     *
     * @param equipementVirtuelList la liste d'equipements virtuels
     * @return le total de capaciteStockage
     */
    public Double getTotalStockage(List<EquipementVirtuel> equipementVirtuelList) {
        Double totalStockage = null;
        if (equipementVirtuelList.stream().noneMatch(vm -> vm.getCapaciteStockage() == null || vm.getCapaciteStockage() == 0)) {
            totalStockage = equipementVirtuelList.stream().mapToDouble(EquipementVirtuel::getCapaciteStockage).sum();
        }
        return totalStockage;
    }
}