package org.mte.numecoeval.calculs.steps;

import io.cucumber.java.DataTableType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mte.numecoeval.calculs.CucumberIntegrationTest;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
import org.mte.numecoeval.calculs.domain.data.demande.OptionsCalcul;
import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
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.referentiel.ReferentielHypothese;
import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielTypeEquipement;

import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mte.numecoeval.calculs.CucumberIntegrationTest.NUMBER_FRENCH_FORMAT;

@Slf4j
public class DataTableTypeDefinitions {

    public static void assertDateIfAvailable(LocalDate valueToTest, Map<String, String> entry, String key) {
        assertEquals(getDateOrNull(entry, key), valueToTest);
    }

    public static void assertDoubleIfAvailable(Double valueToTest, Map<String, String> entry, String key) {
        assertEquals(getDoubleOrNull(entry, key), valueToTest);
    }

    public static void assertIntegerIfAvailable(Integer valueToTest, Map<String, String> entry, String key) {
        assertEquals(getIntegerOrNull(entry, key), valueToTest);
    }

    public static void assertStringIfAvailable(String valueToTest, Map<String, String> entry, String key) {
        assertEquals(entry.getOrDefault(key, null), valueToTest);
    }

    private static LocalDate getDateOrNull(Map<String, String> entry, String key) {
        if (StringUtils.isNotBlank(entry.get(key))) {
            return LocalDate.parse(entry.get(key), CucumberIntegrationTest.FORMATTER_FRENCH_FORMAT);
        }
        return null;
    }

    private static Double getDoubleOrNull(Map<String, String> entry, String key) {
        if (StringUtils.isNotBlank(entry.get(key))) {
            try {
                return NUMBER_FRENCH_FORMAT.parse(entry.get(key)).doubleValue();
            } catch (ParseException e) {
                log.error("Erreur au parsing de la valeur {} : {}", entry.get(key), e.getMessage());
                return null;
            }
        }
        return null;
    }

    private static Integer getIntegerOrNull(Map<String, String> entry, String key) {
        if (StringUtils.isNotBlank(entry.get(key))) {
            try {
                return NUMBER_FRENCH_FORMAT.parse(entry.get(key)).intValue();
            } catch (ParseException e) {
                log.error("Erreur au parsing de la valeur {} : {}", entry.get(key), e.getMessage());
                return null;
            }
        }
        return null;
    }

    @DataTableType
    public DemandeCalculImpactEquipementPhysique demandeCalculImpactEquipementPhysique(Map<String, String> entry) {
        var builder = DemandeCalculImpactEquipementPhysique.builder()
                .dateCalcul(LocalDateTime.now())
                .optionsCalcul(new OptionsCalcul("REEL"))
                .equipementPhysique(
                        EquipementPhysique.builder()
                                .nomEquipementPhysique(entry.getOrDefault("nomEquipementPhysique", null))
                                .dateAchat(getDateOrNull(entry, "dateAchat"))
                                .dateRetrait(getDateOrNull(entry, "dateRetrait"))
                                .build()
                );
        var hypotheses = new ArrayList<ReferentielHypothese>();

        if (StringUtils.isNotBlank(entry.get("refTypeEquipement.dureeVieDefaut"))) {
            builder.typeEquipement(
                    ReferentielTypeEquipement.builder()
                            .dureeVieDefaut(getDoubleOrNull(entry, "refTypeEquipement.dureeVieDefaut"))
                            .build()
            );
        }

        if (StringUtils.isNotBlank(entry.get("hypothese.dureeVieParDefaut"))) {
            hypotheses.add(
                    ReferentielHypothese.builder()
                            .code("dureeVieParDefaut")
                            .valeur(getDoubleOrNull(entry, "hypothese.dureeVieParDefaut"))
                            .build()
            );
        }

        builder.hypotheses(hypotheses);

        return builder.build();
    }

    @DataTableType
    public DemandeCalculImpactEquipementVirtuel demandeCalculImpactEquipementVirtuel(Map<String, String> entry) {
        var builder = DemandeCalculImpactEquipementVirtuel.builder()
                .dateCalcul(LocalDateTime.now())
                .nbEquipementsVirtuels(getIntegerOrNull(entry, "nbEquipementsVirtuels"))
                .nbTotalVCPU(getIntegerOrNull(entry, "nbTotalVCPU"))
                .stockageTotalVirtuel(getDoubleOrNull(entry, "stockageTotalVirtuel"))
                .equipementVirtuel(
                        EquipementVirtuel.builder()
                                .nomLot(entry.getOrDefault("equipementVirtuel.nomLot", null))
                                .dateLot(getDateOrNull(entry, "equipementVirtuel.dateLot"))
                                .nomOrganisation(entry.getOrDefault("equipementVirtuel.nomOrganisation", null))
                                .nomEntite(entry.getOrDefault("equipementVirtuel.nomEntite", null))
                                .nomSourceDonnee(entry.getOrDefault("equipementVirtuel.nomSourceDonnee", null))
                                .nomEquipementVirtuel(entry.getOrDefault("equipementVirtuel.nomEquipementVirtuel", null))
                                .cluster(entry.getOrDefault("equipementVirtuel.cluster", null))
                                .nomEquipementPhysique(entry.getOrDefault("equipementVirtuel.nomEquipementPhysique", null))
                                .typeEqv(entry.getOrDefault("equipementVirtuel.typeEqv", null))
                                .vCPU(getIntegerOrNull(entry, "equipementVirtuel.vCPU"))
                                .consoElecAnnuelle(getDoubleOrNull(entry, "equipementVirtuel.consoElecAnnuelle"))
                                .capaciteStockage(getDoubleOrNull(entry, "equipementVirtuel.capaciteStockage"))
                                .cleRepartition(getDoubleOrNull(entry, "equipementVirtuel.cleRepartition"))
                                .build()
                );

        var impactEquipement = ImpactEquipementPhysique.builder().build();
        impactEquipement.setStatutIndicateur(entry.getOrDefault("impactEquipementPhysique.statutIndicateur", null));
        impactEquipement.setEtapeACV(entry.getOrDefault("impactEquipementPhysique.etape", null));
        impactEquipement.setCritere(entry.getOrDefault("impactEquipementPhysique.critere", null));
        impactEquipement.setUnite(entry.getOrDefault("impactEquipementPhysique.unite", null));
        impactEquipement.setNomLot(entry.getOrDefault("impactEquipementPhysique.nomLot", null));
        impactEquipement.setNomOrganisation(entry.getOrDefault("impactEquipementPhysique.nomOrganisation", null));
        impactEquipement.setDateLot(getDateOrNull(entry, "impactEquipementPhysique.dateLot"));
        impactEquipement.setNomEntite(entry.getOrDefault("impactEquipementPhysique.nomEntite", null));
        if (StringUtils.isNotBlank(entry.get("impactEquipementPhysique.impactUnitaire"))) {
            impactEquipement.setImpactUnitaire(getDoubleOrNull(entry, "impactEquipementPhysique.impactUnitaire"));
        }
        if (StringUtils.isNotBlank(entry.get("impactEquipementPhysique.consoElecMoyenne"))) {
            impactEquipement.setConsoElecMoyenne(getDoubleOrNull(entry, "impactEquipementPhysique.consoElecMoyenne"));
        }
        builder.impactEquipement(impactEquipement);

        return builder.build();
    }
}
