package org.mte.numecoeval.expositiondonneesentrees.infrastructure.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique;
import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.MessageProperties;

import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@ExtendWith(MockitoExtension.class)
public class ErrorManagementServiceTest {
    @Mock
    MessageProperties messageProperties;
    @InjectMocks
    ErrorManagementService errorManagementService;
    @Mock
    ReferentielServicePort referentielServicePort;

    private Map<String, String> messages = new HashMap<>();

    @BeforeEach
    public void init() {
        List<String> modeUtilisationList = new ArrayList<>();
        errorManagementService = new ErrorManagementService(messageProperties, referentielServicePort, modeUtilisationList);
        messages.put("LIGNE_INCONSISTENTE", "Fichier %s , La ligne n°%d n'est pas consistente avec les headers du fichier");
        messages.put("LIGNE_INCORRECTE", "Fichier %s , La ligne n°%d est incorrecte pour l'objet %s requise");
        messages.put("TYPE_EQUIPEMENT_INCONNU", "Le type d'équipement %s correspondant à l'équipement %s n'existe pas dans la table des références ref_TypeEquipement");
        messages.put("EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE", "Le pays %s correspondant à l'équipement physique %s n'existe pas dans la table des mix électriques ref_MixElec.pays");
        messages.put("DATACENTER_MIX_ELEC_LOCALISATION_INCONNUE", "La localisation %s du centre de données %s n'existe pas dans la table des mix électriques ref_MixElec.pays");
        messages.put("EQUIPEMENT_CORRESPONDANCE_INCONNUE", "L'équipement %s de type %s ne possède pas de référence d'équipement par défaut dans la table ref_typeEquipement et pas de correspondance dans la table ref_CorrespondanceRefEqP");
        messages.put("EQUIPEMENT_IMPACT_INCONNU", "L'impact de l'équipement de référence %s pour l'étape %s et le critère %s ne pourra pas être calculé en raison de l'absence de facteur d'impact sur l'équipement");
        messages.put("EQUIPEMENT_DATE_INCOHERENTE", "L'âge de l'équipement %s ne peut être calculé car sa date de retrait précède sa date d'achat");
        messages.put("EQUIPEMENT_MODE_UTILISATION_INCONNU", "Le mode d'utilisation renseigné '%s' est inconnu du référentiel");
        messages.put("EQUIPEMENT_TAUX_UTILISATION_INVALIDE", "Le taux d'utilisation renseigné '%s' n'est pas valide, il doit être compris entre 0 et 1, le taux par défaut sera appliqué.");
        messages.put("EQUIPEMENT_DATACENTER_INCONNU", "L'équipement %s n'est lié à aucun datacenter");
        messages.put("EQUIPEMENT_VIRTUEL_INCONNU", "L'équipement virtuel %s n'est supporté par aucun équipement physique");
        messages.put("APPLICATION_AVEC_EQUIPEMENT_PHYSIQUE_INCONNU", "L'application %s n'est supporté par aucun équipement physique");
        messages.put("APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU", "L'application %s n'est supporté par aucun équipement virtuel");
        Mockito.lenient().when(messageProperties.getMessages()).thenReturn(messages);
    }

    @Test
    void importEqPhysique_with_DateEntreeAfterDateRetrait_shouldReturnReportWith1Error() throws IOException {
        EquipementPhysique eq1 = EquipementPhysique.builder()
                .nomEquipementPhysique("physical-eq-001")
                .modele("P2719")
                .quantite(1.0)
                .dateAchat(LocalDate.of(2023, 3, 30))
                .dateRetrait(LocalDate.of(2023, 1, 17))
                .type("Monitor")
                .statut("In use")
                .paysDUtilisation("France")
                .modeUtilisation("COPE").build();

        var actual = errorManagementService.checkEquipementPhysique(eq1, "");
        assertTrue(actual.getKey().stream().anyMatch(ds -> "L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat".equals(ds)));
    }

    @Test
    void importEqPhysique_with_DateEntreeAfterDateRetrait_shouldNotReturnReportWith1Error() throws IOException {
        EquipementPhysique eq1 = EquipementPhysique.builder()
                .nomEquipementPhysique("physical-eq-001")
                .modele("P2719")
                .quantite(1.0)
                .dateAchat(LocalDate.of(2021, 3, 30))
                .dateRetrait(LocalDate.of(2023, 1, 17))
                .type("Monitor")
                .statut("In use")
                .paysDUtilisation("France")
                .modeUtilisation("COPE").build();

        var actual = errorManagementService.checkEquipementPhysique(eq1, "");
        assertFalse(actual.getKey().stream().anyMatch(ds -> "L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat".equals(ds)));
    }
}
