package com.example.cezenPBX.controller;

import com.example.cezenPBX.DTO.PsEndPointsDTO;
import com.example.cezenPBX.service.BasicPbxService;
import com.example.cezenPBX.service.BasicPbxServiceInterface;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.mockito.ArgumentMatchers.*;


@WebMvcTest(CezenPbxController.class)
@MockBean({BasicPbxService.class})
public class CezenPbxHTTPControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private BasicPbxServiceInterface basicPbxServiceInterface;

    // test for exception when user passes null value
    @Test
    @DisplayName("Null value input")
    void testCreateEndpoint_whenUserEntersNullValues_thenAppMustReturn400() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
        );

        httpTestSupportForEndpointCreation(psEndPointsDTO, 400);
    }

    @Test
    @DisplayName("1001 value input")
    void testCreateEndpoint_whenUserEntersProperValue_thenAppMustReturn200() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                "1001",
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
        );

        httpTestSupportForEndpointCreation(psEndPointsDTO, 200);
    }

    @Test
    @DisplayName("Empty value input")
    void testCreateEndpoint_whenUserEntersNullValues_thenAppMustThrowException() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                "",
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
        );
        httpTestSupportForEndpointCreation(psEndPointsDTO, 400);
    }

    @Test
    @DisplayName("Wrong Email Format input")
    void testCreateEndpoint_whenUserEntersWrongEmailFormat_thenAppMustThrowException() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                "1001",
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                "mathew"
        );

        httpTestSupportForEndpointCreation(psEndPointsDTO, 400);
    }

    @Test
    @DisplayName("Correct email format")
    void testCreateEndpoint_whenUserEntersCorrectEmailFormat_thenAppMustReturn200() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                "1001",
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                "mathew@gmail.com"
        );

        httpTestSupportForEndpointCreation(psEndPointsDTO, 200);
    }

    private void httpTestSupportForEndpointCreation(PsEndPointsDTO psEndPointsDTO, final int testHttpStatus) throws Exception {

        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/cezen/add_user")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsBytes(psEndPointsDTO));

        // Act
        // get the result of the simulated post request
        MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();

        // Assert
        Assertions.assertEquals(testHttpStatus, mvcResult.getResponse().getStatus(), "Incorrect HTTP Status code");

    }


    // database error or duplicate value check
    @Test
    @DisplayName("JDBC returns true when value attempts to persist and values checks out")
    void testCreateEndpoint_whenUserEntersDuplicateValue_thenAppReturnFalse() throws Exception {

        //ModelMapper modelMapper = new ModelMapper();

        // create a new object for an endpoint DTO
        PsEndPointsDTO psEndPointsDTO = new PsEndPointsDTO(
                "1005",
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
        );

        // now mock psEndPoints and basicPbxServiceInterface
        Mockito.when(basicPbxServiceInterface.createANewEndpointService(
                eq("1005"),             // Arg 1: psEndPointsRecordDTO.id()
                isNull(String.class),   // Arg 2: psEndPointsRecordDTO.transport() - is null
                eq("1005"),             // Arg 3: psEndPointsRecordDTO.id() again
                eq("1005"),             // Arg 4: psEndPointsRecordDTO.id() again
                isNull(String.class),   // Arg 5: psEndPointsRecordDTO.context() - is null
                isNull(String.class),   // Arg 6: psEndPointsRecordDTO.disallow() - is null
                isNull(String.class),   // Arg 7: psEndPointsRecordDTO.allow() - is null
                isNull(String.class),   // Arg 8: psEndPointsRecordDTO.directMedia() - is null
                isNull(String.class),   // Arg 9: psEndPointsRecordDTO.connectedLineMethod() - is null
                isNull(String.class),   // Arg 10: psEndPointsRecordDTO.callerid() - is null
                isNull(String.class),   // Arg 11: psEndPointsRecordDTO.dtmfMode() - is null
                isNull(String.class),   // Arg 12: psEndPointsRecordDTO.mohsuggest() - is null
                isNull(String.class)
        )).thenReturn(true);



        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/cezen/add_user")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsBytes(psEndPointsDTO));

        // Act
        // get the result of the simulated post request
        MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();

        // --- Get the Response ---
        MockHttpServletResponse response = mvcResult.getResponse();
        String responseBody = response.getContentAsString();
        // --- --- --- --- --- ---

        Assertions.assertEquals("true",  responseBody);
    }

}
