package com.mosquito.project.persistence.repository;

import com.mosquito.project.persistence.entity.UserInviteEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.TestPropertySource;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;

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

/**
 * UserInviteRepository 数据访问层测试
 * 测试用户邀请记录的CRUD操作和自定义查询方法
 */
@DataJpaTest
@org.springframework.context.annotation.Import(com.mosquito.project.config.TestCacheConfig.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
@TestPropertySource(properties = {
        "spring.cache.type=NONE",
        "spring.jpa.hibernate.ddl-auto=create-drop",
        "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration"
})
class UserInviteRepositoryTest {

    @Autowired
    private UserInviteRepository userInviteRepository;

    private static final Long ACTIVITY_ID_1 = 1L;
    private static final Long ACTIVITY_ID_2 = 2L;
    private static final Long USER_1 = 101L;
    private static final Long USER_2 = 102L;
    private static final Long USER_3 = 103L;
    private static final Long USER_4 = 104L;
    private OffsetDateTime now;

    @BeforeEach
    void setUp() {
        now = OffsetDateTime.now(ZoneOffset.UTC);
        userInviteRepository.deleteAll();
    }

    @Test
    void shouldSaveAndFindUserInviteById() {
        // 创建邀请记录
        UserInviteEntity invite = createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted");
        UserInviteEntity saved = userInviteRepository.save(invite);

        // 验证保存
        assertNotNull(saved.getId(), "保存后ID不应为空");
        assertEquals(ACTIVITY_ID_1, saved.getActivityId());

        // 通过ID查询
        UserInviteEntity found = userInviteRepository.findById(saved.getId()).orElseThrow();
        assertEquals(USER_1, found.getInviterUserId());
        assertEquals(USER_2, found.getInviteeUserId());
    }

    @Test
    void shouldFindByActivityId() {
        // 为活动1创建多个邀请记录
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_3, "pending"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_2, USER_4, "accepted"));

        // 为活动2创建记录（应该被排除）
        userInviteRepository.save(createInvite(ACTIVITY_ID_2, USER_1, USER_3, "accepted"));

        // 查询活动1的所有邀请
        List<UserInviteEntity> invites = userInviteRepository.findByActivityId(ACTIVITY_ID_1);

        // 验证
        assertEquals(3, invites.size(), "活动1应该有3个邀请记录");
        assertTrue(invites.stream().allMatch(i -> i.getActivityId().equals(ACTIVITY_ID_1)),
                "所有记录都应属于活动1");
    }

    @Test
    void shouldFindByActivityIdAndInviterUserId() {
        // 创建不同活动、不同邀请人的记录
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_3, "pending"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_2, USER_4, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_2, USER_1, USER_4, "accepted"));

        // 查询活动1中用户1的邀请记录
        List<UserInviteEntity> invites = userInviteRepository.findByActivityIdAndInviterUserId(ACTIVITY_ID_1, USER_1);

        // 验证
        assertEquals(2, invites.size(), "活动1中用户1应该有2个邀请记录");
        assertTrue(invites.stream().allMatch(i -> i.getInviterUserId().equals(USER_1)),
                "所有记录都应属于用户1");
        assertTrue(invites.stream().allMatch(i -> i.getActivityId().equals(ACTIVITY_ID_1)),
                "所有记录都应属于活动1");
    }

    @Test
    void shouldCountInvitesByActivityIdGroupByInviter() {
        // 创建测试数据
        // 活动1中：用户1邀请2人，用户2邀请1人
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_3, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_2, USER_4, "accepted"));

        // 活动2中：用户1邀请1人（应该被排除）
        userInviteRepository.save(createInvite(ACTIVITY_ID_2, USER_1, USER_4, "accepted"));

        // 执行统计查询
        List<Object[]> results = userInviteRepository.countInvitesByActivityIdGroupByInviter(ACTIVITY_ID_1);

        // 验证
        assertEquals(2, results.size(), "应该有2个邀请人");

        // 验证排序（按邀请数量降序）
        Object[] first = results.get(0);
        assertEquals(USER_1, first[0], "用户1应该是第一名（邀请最多）");
        assertEquals(2L, first[1], "用户1应该邀请了2人");

        Object[] second = results.get(1);
        assertEquals(USER_2, second[0], "用户2应该是第二名");
        assertEquals(1L, second[1], "用户2应该邀请了1人");
    }

    @Test
    void shouldCountByActivityId() {
        // 创建测试数据
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, USER_3, "pending"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_2, USER_4, "accepted"));
        userInviteRepository.save(createInvite(ACTIVITY_ID_2, USER_1, USER_4, "accepted"));

        // 统计活动1的邀请总数
        long count = userInviteRepository.countByActivityId(ACTIVITY_ID_1);

        // 验证
        assertEquals(3, count, "活动1应该有3个邀请记录");
    }

    @Test
    void shouldReturnEmptyListForNonExistentActivity() {
        // 查询不存在的活动
        List<UserInviteEntity> invites = userInviteRepository.findByActivityId(999L);
        assertTrue(invites.isEmpty(), "不存在的活动应该返回空列表");
    }

    @Test
    void shouldEnforceUniqueConstraint() {
        // 创建第一条记录
        UserInviteEntity invite1 = createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted");
        userInviteRepository.save(invite1);

        // 创建重复的记录（相同活动和被邀请人）
        UserInviteEntity invite2 = createInvite(ACTIVITY_ID_1, USER_3, USER_2, "pending");

        // 验证违反唯一约束
        assertThrows(Exception.class, () -> {
            userInviteRepository.saveAndFlush(invite2);
        }, "重复的活动ID和被邀请人ID组合应该违反唯一约束");
    }

    @Test
    void shouldAllowSameInviteeInDifferentActivities() {
        // 同一被邀请人在不同活动中应该允许
        UserInviteEntity invite1 = createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted");
        UserInviteEntity invite2 = createInvite(ACTIVITY_ID_2, USER_3, USER_2, "accepted");

        assertDoesNotThrow(() -> {
            userInviteRepository.save(invite1);
            userInviteRepository.save(invite2);
        }, "同一被邀请人在不同活动中应该允许");

        // 验证保存成功
        assertEquals(2, userInviteRepository.count());
    }

    @Test
    void shouldUpdateInviteStatus() {
        // 创建初始记录
        UserInviteEntity invite = createInvite(ACTIVITY_ID_1, USER_1, USER_2, "pending");
        UserInviteEntity saved = userInviteRepository.save(invite);

        // 更新状态
        saved.setStatus("accepted");
        saved.setCreatedAt(now.plusMinutes(5));
        userInviteRepository.save(saved);

        // 验证更新
        UserInviteEntity updated = userInviteRepository.findById(saved.getId()).orElseThrow();
        assertEquals("accepted", updated.getStatus(), "状态应该更新为accepted");
    }

    @Test
    void shouldDeleteInvite() {
        // 创建并保存记录
        UserInviteEntity invite = createInvite(ACTIVITY_ID_1, USER_1, USER_2, "accepted");
        UserInviteEntity saved = userInviteRepository.save(invite);

        // 删除
        userInviteRepository.deleteById(saved.getId());

        // 验证删除
        assertFalse(userInviteRepository.existsById(saved.getId()), "删除后应该不存在");
        assertEquals(0, userInviteRepository.countByActivityId(ACTIVITY_ID_1), "活动邀请计数应该为0");
    }

    @Test
    void shouldHandleLargeInviteCount() {
        // 批量创建100个邀请记录
        for (int i = 0; i < 100; i++) {
            Long inviteeId = 1000L + i;
            userInviteRepository.save(createInvite(ACTIVITY_ID_1, USER_1, inviteeId, "accepted"));
        }

        // 验证统计
        long count = userInviteRepository.countByActivityId(ACTIVITY_ID_1);
        assertEquals(100, count, "应该有100个邀请记录");

        List<Object[]> results = userInviteRepository.countInvitesByActivityIdGroupByInviter(ACTIVITY_ID_1);
        assertEquals(1, results.size(), "应该只有1个邀请人");
        assertEquals(100L, results.get(0)[1], "用户1应该邀请了100人");
    }

    /**
     * 辅助方法：创建邀请实体
     */
    private UserInviteEntity createInvite(Long activityId, Long inviterId, Long inviteeId, String status) {
        UserInviteEntity invite = new UserInviteEntity();
        invite.setActivityId(activityId);
        invite.setInviterUserId(inviterId);
        invite.setInviteeUserId(inviteeId);
        invite.setStatus(status);
        invite.setCreatedAt(now);
        return invite;
    }
}
