package cn.novalon.manage.sys.primitive;

import cn.novalon.manage.common.exception.ValidationException;
import org.junit.jupiter.api.Test;

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

class PasswordTest {

    @Test
    void testOf_ValidPassword() {
        Password password = Password.of("Test@123");
        assertEquals("Test@123", password.getValue());
    }

    @Test
    void testOf_NullPassword() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of(null));
        assertEquals("Password is required", exception.getMessage());
    }

    @Test
    void testOf_EmptyPassword() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of(""));
        assertEquals("Password is required", exception.getMessage());
    }

    @Test
    void testOf_WhitespaceOnlyPassword() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("   "));
        assertEquals("Password is required", exception.getMessage());
    }

    @Test
    void testOf_TooShortPassword() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("Test@1"));
        assertEquals("Password must be at least 8 characters long", exception.getMessage());
    }

    @Test
    void testOf_NoUppercase() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("test@123"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }

    @Test
    void testOf_NoLowercase() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("TEST@123"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }

    @Test
    void testOf_NoDigit() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("Test@abc"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }

    @Test
    void testOf_NoSpecialCharacter() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("Test1234"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }

    @Test
    void testOf_MinLengthBoundary() {
        Password password = Password.of("Test@123");
        assertEquals("Test@123", password.getValue());
    }

    @Test
    void testOf_LongPassword() {
        Password password = Password.of("VeryLongPassword@123456");
        assertEquals("VeryLongPassword@123456", password.getValue());
    }

    @Test
    void testOf_WithMultipleSpecialCharacters() {
        Password password = Password.of("Test@#$%123");
        assertEquals("Test@#$%123", password.getValue());
    }

    @Test
    void testOf_WithUnderscore() {
        Password password = Password.of("Test_123");
        assertEquals("Test_123", password.getValue());
    }

    @Test
    void testOf_WithHyphen() {
        Password password = Password.of("Test-123");
        assertEquals("Test-123", password.getValue());
    }

    @Test
    void testEquals_SameValue() {
        Password password1 = Password.of("Test@123");
        Password password2 = Password.of("Test@123");
        assertEquals(password1, password2);
    }

    @Test
    void testEquals_DifferentValue() {
        Password password1 = Password.of("Test@123");
        Password password2 = Password.of("Test@456");
        assertNotEquals(password1, password2);
    }

    @Test
    void testEquals_SameObject() {
        Password password = Password.of("Test@123");
        assertEquals(password, password);
    }

    @Test
    void testEquals_Null() {
        Password password = Password.of("Test@123");
        assertNotEquals(password, null);
    }

    @Test
    void testEquals_DifferentClass() {
        Password password = Password.of("Test@123");
        assertNotEquals(password, "Test@123");
    }

    @Test
    void testHashCode_SameValue() {
        Password password1 = Password.of("Test@123");
        Password password2 = Password.of("Test@123");
        assertEquals(password1.hashCode(), password2.hashCode());
    }

    @Test
    void testHashCode_DifferentValue() {
        Password password1 = Password.of("Test@123");
        Password password2 = Password.of("Test@456");
        assertNotEquals(password1.hashCode(), password2.hashCode());
    }

    @Test
    void testToString() {
        Password password = Password.of("Test@123");
        assertEquals("********", password.toString());
    }

    @Test
    void testOf_WithSpacesInPassword() {
        Password password = Password.of("Test @123");
        assertEquals("Test @123", password.getValue());
    }

    @Test
    void testOf_WithUnicodeCharacters() {
        Password password = Password.of("Tëst@123");
        assertEquals("Tëst@123", password.getValue());
    }

    @Test
    void testOf_WithNumbersOnly() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("12345678"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }

    @Test
    void testOf_WithLettersOnly() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Password.of("TestTest"));
        assertEquals(
                "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character",
                exception.getMessage());
    }
}
