package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeitem;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
import org.mte.numecoeval.referentiel.factory.TestDataFactory;
import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeItemCsvExportService;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO;
import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeItemFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.server.ResponseStatusException;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ContextConfiguration(classes = {ReferentielTypeItemRestApiImpl.class})
@ExtendWith(SpringExtension.class)
class ReferentielTypeItemRestApiImplTest {
    @Autowired
    private ReferentielTypeItemRestApiImpl referentielRestApi;

    @MockBean
    private TypeItemFacade referentielFacade;

    @MockBean
    private TypeItemCsvExportService csvExportService;

    @Test
    void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() {
        ArrayList<TypeItemDTO> typeItemDTOS = new ArrayList<>();
        when(referentielFacade.getAllTypesItem()).thenReturn(typeItemDTOS);

        List<TypeItemDTO> actualAll = referentielRestApi.getTypesItem();

        assertSame(typeItemDTOS, actualAll);
        assertTrue(actualAll.isEmpty());
        verify(referentielFacade).getAllTypesItem();
    }

    @Test
    void getTypeItem_shouldCallFacadeGetAndReturnDTO() throws ReferentielException {

        String expectedType = "Serveur";
        TypeItemDTO expectedDTO = TestDataFactory.TypeItemFactory.dto(expectedType, null, true, "Exemple de serveur basique",
                6.0, null, "NegaOctet", "serveur_par_defaut");
        when(referentielFacade.getTypeItemForType(expectedType)).thenReturn(expectedDTO);

        TypeItemDTO actualResponse = referentielRestApi.getTypeItem(expectedType);

        assertSame(expectedDTO, actualResponse);
        verify(referentielFacade).getTypeItemForType(expectedType);
    }

    @Test
    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
        doNothing().when(referentielFacade).purgeAndAddAll(any());

        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));

        verify(referentielFacade).purgeAndAddAll(any());
    }

    @Test
    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
        doNothing().when(referentielFacade).purgeAndAddAll(any());
        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);

        ResponseStatusException responseStatusException = assertThrows(
                ResponseStatusException.class,
                () -> referentielRestApi.importCSV(file)
        );

        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
    }

    @Test
    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
        doNothing().when(referentielFacade).purgeAndAddAll(any());

        ResponseStatusException responseStatusException = assertThrows(
                ResponseStatusException.class,
                () -> referentielRestApi.importCSV(null)
        );

        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
    }

    @Test
    void exportCSV_shouldReturnCSVFile() {
        var servletResponse = new MockHttpServletResponse();

        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));

        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
        assertNotNull(headerContentDisposition);
        assertTrue(headerContentDisposition.contains("attachment; filename=typeItem-"));
        assertEquals(200, servletResponse.getStatus());

    }
}
