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 EmailTest {

    @Test
    void testOf_ValidEmail() {
        Email email = Email.of("test@example.com");
        assertEquals("test@example.com", email.getValue());
    }

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

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

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

    @Test
    void testOf_InvalidEmail_NoAtSymbol() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("testexample.com")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_InvalidEmail_NoDomain() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("test@")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_InvalidEmail_NoTLD() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("test@example")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_InvalidEmail_ShortTLD() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("test@example.c")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_ValidEmail_WithSubdomain() {
        Email email = Email.of("test@mail.example.com");
        assertEquals("test@mail.example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithPlus() {
        Email email = Email.of("test+label@example.com");
        assertEquals("test+label@example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithUnderscore() {
        Email email = Email.of("test_user@example.com");
        assertEquals("test_user@example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithHyphen() {
        Email email = Email.of("test-user@example.com");
        assertEquals("test-user@example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithDot() {
        Email email = Email.of("test.user@example.com");
        assertEquals("test.user@example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithNumbers() {
        Email email = Email.of("test123@example.com");
        assertEquals("test123@example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithMultipleDotsInDomain() {
        Email email = Email.of("test@example.co.uk");
        assertEquals("test@example.co.uk", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithHyphenInDomain() {
        Email email = Email.of("test@example-domain.com");
        assertEquals("test@example-domain.com", email.getValue());
    }

    @Test
    void testOfNullable_NullValue() {
        Email email = Email.ofNullable(null);
        assertNull(email);
    }

    @Test
    void testOfNullable_EmptyValue() {
        Email email = Email.ofNullable("");
        assertNull(email);
    }

    @Test
    void testOfNullable_WhitespaceValue() {
        Email email = Email.ofNullable("   ");
        assertNull(email);
    }

    @Test
    void testOfNullable_ValidEmail() {
        Email email = Email.ofNullable("test@example.com");
        assertNotNull(email);
        assertEquals("test@example.com", email.getValue());
    }

    @Test
    void testEquals_SameValue() {
        Email email1 = Email.of("test@example.com");
        Email email2 = Email.of("test@example.com");
        assertEquals(email1, email2);
    }

    @Test
    void testEquals_DifferentValue() {
        Email email1 = Email.of("test1@example.com");
        Email email2 = Email.of("test2@example.com");
        assertNotEquals(email1, email2);
    }

    @Test
    void testEquals_SameObject() {
        Email email = Email.of("test@example.com");
        assertEquals(email, email);
    }

    @Test
    void testEquals_Null() {
        Email email = Email.of("test@example.com");
        assertNotEquals(email, null);
    }

    @Test
    void testEquals_DifferentClass() {
        Email email = Email.of("test@example.com");
        assertNotEquals(email, "test@example.com");
    }

    @Test
    void testHashCode_SameValue() {
        Email email1 = Email.of("test@example.com");
        Email email2 = Email.of("test@example.com");
        assertEquals(email1.hashCode(), email2.hashCode());
    }

    @Test
    void testHashCode_DifferentValue() {
        Email email1 = Email.of("test1@example.com");
        Email email2 = Email.of("test2@example.com");
        assertNotEquals(email1.hashCode(), email2.hashCode());
    }

    @Test
    void testToString() {
        Email email = Email.of("test@example.com");
        assertEquals("test@example.com", email.toString());
    }

    @Test
    void testOf_ValidEmail_WithLeadingTrailingWhitespace() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("  test@example.com  ")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_ValidEmail_WithNumbersInDomain() {
        Email email = Email.of("test@123example.com");
        assertEquals("test@123example.com", email.getValue());
    }

    @Test
    void testOf_ValidEmail_WithMultipleAtSymbols() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("test@@example.com")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }

    @Test
    void testOf_ValidEmail_WithSpecialCharsInLocalPart() {
        ValidationException exception = assertThrows(
                ValidationException.class,
                () -> Email.of("test!#$%&'*+/=?^_`{|}~-@example.com")
        );
        assertEquals("Invalid email format", exception.getMessage());
    }
}
