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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.junit.jupiter.api.Assertions;
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.calculs.domain.model.CalculSizes;
import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository;
import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository;
import org.mte.numecoeval.calculs.infrastructure.repository.OperationNonITRepository;
import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService;
import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService;
import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainOperationNonITService;
import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest;
import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
import org.mte.numecoeval.topic.data.MessagerieDTO;
import org.mte.numecoeval.topic.data.OperationNonITDTO;

import java.util.List;

import static org.mockito.ArgumentMatchers.any;

@ExtendWith(MockitoExtension.class)
class SyncCalculServiceTest {

    @InjectMocks
    SyncCalculService syncCalculService;

    @Mock
    EquipementPhysiqueRepository equipementPhysiqueRepository;
    @Mock
    MainEquipementPhysiqueService mainEquipementPhysiqueService;
    @Mock
    OperationNonITRepository operationNonITRepository;
    @Mock
    MainOperationNonITService mainOperationNonITService;
    @Mock
    MessagerieRepository messagerieRepository;
    @Mock
    MainMessagerieService mainMessagerieService;

    private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());

    @Test
    void testSyncCalculService_withListEquipementPhysique() throws JsonProcessingException {
        /* MOCKS */
        Mockito.when(equipementPhysiqueRepository.findEquipementPhysiqueDTOs(any())).thenReturn(List.of(
                new EquipementPhysiqueDTO(),
                new EquipementPhysiqueDTO()
        ));

        var calculSizes = new CalculSizes();
        calculSizes.setNbEquipementPhysique(1);
        calculSizes.setNbEquipementVirtuel(2);
        calculSizes.setNbApplication(3);

        Mockito.when(mainEquipementPhysiqueService.calcul(any())).thenReturn(calculSizes);

        var syncCalculRest = new SyncCalculRest();
        syncCalculRest.setEquipementPhysiqueIds(List.of(1L, 2L));

        /* EXECUTE */
        var actual = syncCalculService.calcul(syncCalculRest);

        /* ASSERT */
        Assertions.assertEquals(2, actual.getNbrEquipementPhysique());
        Assertions.assertEquals(4, actual.getNbrEquipementVirtuel());
        Assertions.assertEquals(6, actual.getNbrApplication());
    }

    @Test
    void testSyncCalculService_withListMessagerie() throws JsonProcessingException {
        /* MOCKS */
        Mockito.when(messagerieRepository.findMessagerieDTOList(any())).thenReturn(List.of(
                new MessagerieDTO(),
                new MessagerieDTO(),
                new MessagerieDTO()
        ));

        var calculSizes = new CalculSizes();
        calculSizes.setNbMessagerie(1);

        Mockito.when(mainMessagerieService.calcul(any())).thenReturn(calculSizes);

        var syncCalculRest = new SyncCalculRest();
        syncCalculRest.setMessagerieIds(List.of(10L, 20L, 30L));

        /* EXECUTE */
        var actual = syncCalculService.calcul(syncCalculRest);

        /* ASSERT */
        Assertions.assertEquals(3, actual.getNbrMessagerie());
    }

    @Test
    void testSyncCalculService_withListOperationNonIT() throws JsonProcessingException {
        /* MOCKS */
        Mockito.when(operationNonITRepository.findOperationNonITDTOs(any())).thenReturn(List.of(
                new OperationNonITDTO(),
                new OperationNonITDTO()
        ));

        var calculSizes = new CalculSizes();
        calculSizes.setNbOperationNonIT(1);
        calculSizes.setNbEquipementVirtuel(2);
        calculSizes.setNbApplication(3);

        Mockito.when(mainOperationNonITService.calcul(any())).thenReturn(calculSizes);

        var syncCalculRest = new SyncCalculRest();
        syncCalculRest.setOperationNonITIds(List.of(1L, 2L));

        /* EXECUTE */
        var actual = syncCalculService.calcul(syncCalculRest);

        /* ASSERT */
        Assertions.assertEquals(2, actual.getNbrOperationNonIT());
    }
}
