package com.realnet.password_generator;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
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.test.web.servlet.MockMvc;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(PasswordGeneratorController.class)
class PasswordGeneratorControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private PasswordGeneratorService passwordGeneratorService;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void testGeneratePassword_success() throws Exception {
        PasswordGenerationRequest request = new PasswordGenerationRequest(12, true, true, true, true, "");
        PasswordGenerationResponse mockResponse = new PasswordGenerationResponse("GeneratedP@ss1", "Password generated successfully.", true);

        when(passwordGeneratorService.generatePassword(any(PasswordGenerationRequest.class)))
                .thenReturn(mockResponse);

        mockMvc.perform(post("/api/v1/password-generator/generate")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(request)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.generatedPassword").value("GeneratedP@ss1"));
    }

    @Test
    void testGeneratePassword_badRequest_invalidLength() throws Exception {
        PasswordGenerationRequest request = new PasswordGenerationRequest(5, true, true, true, true, "");
        PasswordGenerationResponse mockResponse = new PasswordGenerationResponse(null, "Invalid password length. Must be between 8 and 128 characters.", false);

        when(passwordGeneratorService.generatePassword(any(PasswordGenerationRequest.class)))
                .thenReturn(mockResponse);

        mockMvc.perform(post("/api/v1/password-generator/generate")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(request)))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false))
                .andExpect(jsonPath("$.message").value("Invalid password length. Must be between 8 and 128 characters."));
    }

    @Test
    void testGeneratePassword_badRequest_noCharTypeSelected() throws Exception {
        PasswordGenerationRequest request = new PasswordGenerationRequest(10, false, false, false, false, "");
        PasswordGenerationResponse mockResponse = new PasswordGenerationResponse(null, "At least one character type (uppercase, lowercase, numbers, symbols) must be selected.", false);

        when(passwordGeneratorService.generatePassword(any(PasswordGenerationRequest.class)))
                .thenReturn(mockResponse);

        mockMvc.perform(post("/api/v1/password-generator/generate")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(request)))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false))
                .andExpect(jsonPath("$.message").value("At least one character type (uppercase, lowercase, numbers, symbols) must be selected."));
    }
}
