package org.mte.numecoeval.calculs.domain.port.input.service.impl;

import lombok.AllArgsConstructor;
import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese;
import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVieParDefaut;
import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

@AllArgsConstructor
public class DureeDeVieEquipementPhysiqueServiceImpl implements DureeDeVieEquipementPhysiqueService {

    @Override
    public DureeDeVie calculerDureeVie(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
        var dateAchat = demandeCalcul.getEquipementPhysique().getDateAchat();
        var dateRetrait = demandeCalcul.getEquipementPhysique().getDateRetrait();
        var result = DureeDeVie.builder().build();
        if (dateAchat != null && dateRetrait != null) {

            if (dateAchat.isBefore(dateRetrait)) {
                Double valeur ;
                if (ChronoUnit.MONTHS.between(dateAchat, dateRetrait) < 12) {
                     valeur= 1d;
                } else {
                     valeur = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d;
                }
                result.setValeur(valeur);
                result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE));
                result.setDateRetrait(dateRetrait.format(DateTimeFormatter.ISO_DATE));
            } else {
                throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie de l'équipement n'a pas pu être déterminée");
            }
        }
        // Taiga#864 - Si la date d'achat est présente et non la date de retrait, on prend la date du jour devient la date de retrait pour le calcul
        else if (dateAchat != null) {
            result.setValeur(
                    ChronoUnit.DAYS.between(dateAchat, LocalDate.now()) / 365d
            );
            result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE));
            result.setDateRetrait(LocalDate.now().format(DateTimeFormatter.ISO_DATE));
        }
        else {
            var dureeDeVieParDefaut = calculerDureeVieDefaut(demandeCalcul);
            result.setDureeDeVieParDefaut(dureeDeVieParDefaut);
            result.setValeur(dureeDeVieParDefaut.getValeur());
        }
        return  result;
    }

    @Override
    public DureeDeVieParDefaut calculerDureeVieDefaut(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {

        if(demandeCalcul.getTypeEquipement() != null && demandeCalcul.getTypeEquipement().getDureeVieDefaut() !=null){
            return DureeDeVieParDefaut.builder()
                    .valeurEquipementDureeVieDefaut(demandeCalcul.getTypeEquipement().getDureeVieDefaut())
                    .valeur(demandeCalcul.getTypeEquipement().getDureeVieDefaut())
                    .build();
        }
        var refHypotheseOpt= demandeCalcul.getHypotheseFromCode("dureeVieParDefaut");
        if (refHypotheseOpt.isPresent() && refHypotheseOpt.get().getValeur() != null){
            ReferentielHypothese hypothese = refHypotheseOpt.get();
            return DureeDeVieParDefaut.builder()
                    .valeurReferentielHypothese(hypothese.getValeur())
                    .sourceReferentielHypothese(hypothese.getSource())
                    .valeur(hypothese.getValeur())
                    .build();
        }
        throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie par défaut de l'équipement n'a pas pu être déterminée");
    }

}
