package com.mosquito.project.domain;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

@DisplayName("用户领域模型测试")
class UserTest {

    private User user;
    private final Long TEST_ID = 123L;
    private final String TEST_NAME = "Test User";

    @BeforeEach
    void setUp() {
        user = new User(TEST_ID, TEST_NAME);
    }

    @Test
    @DisplayName("用户构造函数")
    void shouldCreateUser_WithConstructor() {
        // When & Then
        assertEquals(TEST_ID, user.getId());
        assertEquals(TEST_NAME, user.getName());
    }

    @Test
    @DisplayName("设置用户ID")
    void shouldSetUserId() {
        // Given
        Long newId = 456L;

        // When
        user.setId(newId);

        // Then
        assertEquals(newId, user.getId());
        assertNotEquals(TEST_ID, user.getId());
    }

    @Test
    @DisplayName("设置用户名")
    void shouldSetUserName() {
        // Given
        String newName = "Updated User Name";

        // When
        user.setName(newName);

        // Then
        assertEquals(newName, user.getName());
        assertNotEquals(TEST_NAME, user.getName());
    }

    @Test
    @DisplayName("设置空用户名")
    void shouldHandleEmptyName() {
        // Given
        String emptyName = "";

        // When
        user.setName(emptyName);

        // Then
        assertEquals(emptyName, user.getName());
        assertTrue(user.getName().isEmpty());
    }

    @Test
    @DisplayName("设置null用户名")
    void shouldHandleNullName() {
        // When
        user.setName(null);

        // Then
        assertNull(user.getName());
    }

    @Test
    @DisplayName("设置null用户ID")
    void shouldHandleNullId() {
        // When
        user.setId(null);

        // Then
        assertNull(user.getId());
    }

    @Test
    @DisplayName("设置零用户ID")
    void shouldHandleZeroId() {
        // Given
        Long zeroId = 0L;

        // When
        user.setId(zeroId);

        // Then
        assertEquals(zeroId, user.getId());
        assertEquals(0L, user.getId());
    }

    @Test
    @DisplayName("设置负数用户ID")
    void shouldHandleNegativeId() {
        // Given
        Long negativeId = -1L;

        // When
        user.setId(negativeId);

        // Then
        assertEquals(negativeId, user.getId());
        assertEquals(-1L, user.getId());
    }

    @Test
    @DisplayName("用户名包含特殊字符")
    void shouldHandleSpecialCharacters() {
        // Given
        String specialName = "用户🔑123-test_name";

        // When
        user.setName(specialName);

        // Then
        assertEquals(specialName, user.getName());
    }

    @Test
    @DisplayName("很长的用户名")
    void shouldHandleLongName() {
        // Given
        StringBuilder longName = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            longName.append("a");
        }
        String longNameStr = longName.toString();

        // When
        user.setName(longNameStr);

        // Then
        assertEquals(longNameStr, user.getName());
        assertEquals(1000, user.getName().length());
    }

    @Test
    @DisplayName("用户名包含空白字符")
    void shouldHandleWhitespace() {
        // Given
        String whitespaceName = "  User With Spaces  ";

        // When
        user.setName(whitespaceName);

        // Then
        assertEquals(whitespaceName, user.getName());
        assertEquals("  User With Spaces  ", user.getName());
    }

    @Test
    @DisplayName("创建多个用户实例")
    void shouldCreateMultipleUsers() {
        // Given
        User user1 = new User(1L, "User 1");
        User user2 = new User(2L, "User 2");
        User user3 = new User(3L, "User 3");

        // When & Then
        assertNotEquals(user1.getId(), user2.getId());
        assertNotEquals(user2.getId(), user3.getId());
        assertNotEquals(user1.getId(), user3.getId());
        
        assertNotEquals(user1.getName(), user2.getName());
        assertNotEquals(user2.getName(), user3.getName());
        assertNotEquals(user1.getName(), user3.getName());
        
        assertEquals(1L, user1.getId());
        assertEquals("User 1", user1.getName());
        assertEquals(2L, user2.getId());
        assertEquals("User 2", user2.getName());
        assertEquals(3L, user3.getId());
        assertEquals("User 3", user3.getName());
    }

    @Test
    @DisplayName("用户对象相等性")
    void shouldCheckUserEquality() {
        // Given
        User sameUser1 = new User(1L, "Same User");
        User sameUser2 = new User(1L, "Same User");
        User differentUser = new User(2L, "Different User");

        // When & Then - 注意：如果不重写equals方法，这里会使用引用相等
        assertNotEquals(sameUser1, sameUser2); // 不同实例
        assertNotEquals(sameUser1, differentUser); // 不同数据
    }

    @Test
    @DisplayName("用户对象toString")
    void shouldHaveStringRepresentation() {
        // When & Then
        String userString = user.toString();
        assertNotNull(userString);
        // 注意：如果没有重写toString，会使用默认的Object.toString()
        assertTrue(userString.contains("User"));
    }

    @Test
    @DisplayName("用户对象hashCode")
    void shouldHaveHashCode() {
        // Given
        User sameUser = new User(TEST_ID, TEST_NAME);

        // When & Then
        int hashCode1 = user.hashCode();
        int hashCode2 = sameUser.hashCode();
        
        // 如果没有重写hashCode，可能不同；如果重写了，相同对象应该有相同hashCode
        assertNotNull(hashCode1);
        assertNotNull(hashCode2);
    }

    @Test
    @DisplayName("用户ID边界值")
    void shouldHandleBoundaryIds() {
        // Given
        User userWithMaxId = new User(Long.MAX_VALUE, "Max ID User");
        User userWithMinId = new User(Long.MIN_VALUE, "Min ID User");

        // When & Then
        assertEquals(Long.MAX_VALUE, userWithMaxId.getId());
        assertEquals(Long.MIN_VALUE, userWithMinId.getId());
        assertEquals("Max ID User", userWithMaxId.getName());
        assertEquals("Min ID User", userWithMinId.getName());
    }

    @Test
    @DisplayName("用户属性独立性")
    void shouldMaintainPropertyIndependence() {
        // Given
        User user1 = new User(1L, "Original Name");
        User user2 = new User(1L, "Original Name");

        // When - 只修改user1
        user1.setName("Modified Name");
        user1.setId(999L);

        // Then - user2应该保持不变
        assertEquals("Original Name", user2.getName());
        assertEquals(1L, user2.getId());
        
        // user1应该被修改
        assertEquals("Modified Name", user1.getName());
        assertEquals(999L, user1.getId());
    }
}