package com.realnet.password_generator;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;

import static org.junit.jupiter.api.Assertions.*;

class PasswordGeneratorServiceTest {

    @InjectMocks
    private PasswordGeneratorService passwordGeneratorService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testGeneratePassword_validRequest() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(12, true, true, true, true, "");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertTrue(response.isSuccess());
        assertNotNull(response.getGeneratedPassword());
        assertEquals(12, response.getGeneratedPassword().length());
        assertTrue(response.getGeneratedPassword().matches(".*[A-Z].*"));
        assertTrue(response.getGeneratedPassword().matches(".*[a-z].*"));
        assertTrue(response.getGeneratedPassword().matches(".*[0-9].*"));
        assertTrue(response.getGeneratedPassword().matches(".*[^A-Za-z0-9].*"));
    }

    @Test
    void testGeneratePassword_onlyLowercase() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(10, false, true, false, false, "");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertTrue(response.isSuccess());
        assertNotNull(response.getGeneratedPassword());
        assertEquals(10, response.getGeneratedPassword().length());
        assertTrue(response.getGeneratedPassword().matches("[a-z]+"));
    }

    @Test
    void testGeneratePassword_withExclusions() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(10, true, true, true, true, "abc");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertTrue(response.isSuccess());
        assertNotNull(response.getGeneratedPassword());
        assertEquals(10, response.getGeneratedPassword().length());
        assertFalse(response.getGeneratedPassword().contains("a"));
        assertFalse(response.getGeneratedPassword().contains("b"));
        assertFalse(response.getGeneratedPassword().contains("c"));
    }

    @Test
    void testGeneratePassword_invalidLength_tooShort() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(5, true, true, true, true, "");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertFalse(response.isSuccess());
        assertNull(response.getGeneratedPassword());
        assertEquals("Invalid password length. Must be between 8 and 128 characters.", response.getMessage());
    }

    @Test
    void testGeneratePassword_invalidLength_tooLong() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(150, true, true, true, true, "");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertFalse(response.isSuccess());
        assertNull(response.getGeneratedPassword());
        assertEquals("Invalid password length. Must be between 8 and 128 characters.", response.getMessage());
    }

    @Test
    void testGeneratePassword_noCharTypeSelected() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(10, false, false, false, false, "");
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertFalse(response.isSuccess());
        assertNull(response.getGeneratedPassword());
        assertEquals("At least one character type (uppercase, lowercase, numbers, symbols) must be selected.", response.getMessage());
    }

    @Test
    void testGeneratePassword_emptyCharPoolAfterExclusions() {
        PasswordGenerationRequest request = new PasswordGenerationRequest(10, true, false, false, false, UPPERCASE_CHARS);
        PasswordGenerationResponse response = passwordGeneratorService.generatePassword(request);

        assertFalse(response.isSuccess());
        assertNull(response.getGeneratedPassword());
        assertEquals("Character pool is empty after exclusions. Please adjust your selections or exclusions.", response.getMessage());
    }
}
