package com.mosquito.project.persistence.repository;

import com.mosquito.project.persistence.entity.UserRewardEntity;
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.*;

/**
 * UserRewardRepository 数据访问层测试
 * 测试用户奖励记录的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 UserRewardRepositoryTest {

    @Autowired
    private UserRewardRepository userRewardRepository;

    private static final Long ACTIVITY_ID = 1L;
    private static final Long USER_1 = 101L;
    private static final Long USER_2 = 102L;
    private OffsetDateTime now;

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

    @Test
    void shouldSaveAndFindRewardById() {
        // 创建奖励记录
        UserRewardEntity reward = createReward(ACTIVITY_ID, USER_1, "invitation", 100);
        UserRewardEntity saved = userRewardRepository.save(reward);

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

        // 通过ID查询
        UserRewardEntity found = userRewardRepository.findById(saved.getId()).orElseThrow();
        assertEquals("invitation", found.getType());
    }

    @Test
    void shouldFindByActivityIdAndUserIdOrderByCreatedAtDesc() {
        // 为用户1在活动1中创建多个奖励记录（不同时间）
        UserRewardEntity reward1 = createReward(ACTIVITY_ID, USER_1, "invite", 50);
        reward1.setCreatedAt(now.minusHours(2));
        userRewardRepository.save(reward1);

        UserRewardEntity reward2 = createReward(ACTIVITY_ID, USER_1, "share", 30);
        reward2.setCreatedAt(now.minusHours(1));
        userRewardRepository.save(reward2);

        UserRewardEntity reward3 = createReward(ACTIVITY_ID, USER_1, "click", 10);
        reward3.setCreatedAt(now);
        userRewardRepository.save(reward3);

        // 为用户2在活动1中创建记录（应该被排除）
        userRewardRepository.save(createReward(ACTIVITY_ID, USER_2, "invite", 50));

        // 为用户1在活动2中创建记录（应该被排除）
        userRewardRepository.save(createReward(2L, USER_1, "invite", 50));

        // 查询
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(ACTIVITY_ID, USER_1);

        // 验证
        assertEquals(3, rewards.size(), "应该返回3条记录");

        // 验证按时间降序排序
        assertEquals("click", rewards.get(0).getType(), "最新的记录应该是click");
        assertEquals("share", rewards.get(1).getType(), "中间应该是share");
        assertEquals("invite", rewards.get(2).getType(), "最旧的应该是invite");
    }

    @Test
    void shouldReturnEmptyListForNonExistentUserOrActivity() {
        // 查询不存在的用户
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(999L, 999L);
        assertTrue(rewards.isEmpty(), "不存在的用户或活动应该返回空列表");
    }

    @Test
    void shouldUpdateRewardPoints() {
        // 创建初始记录
        UserRewardEntity reward = createReward(ACTIVITY_ID, USER_1, "bonus", 50);
        UserRewardEntity saved = userRewardRepository.save(reward);

        // 更新积分
        saved.setPoints(100);
        userRewardRepository.save(saved);

        // 验证更新
        UserRewardEntity updated = userRewardRepository.findById(saved.getId()).orElseThrow();
        assertEquals(100, updated.getPoints(), "积分应该更新为100");
    }

    @Test
    void shouldDeleteReward() {
        // 创建并保存记录
        UserRewardEntity reward = createReward(ACTIVITY_ID, USER_1, "invite", 50);
        UserRewardEntity saved = userRewardRepository.save(reward);
        Long id = saved.getId();

        // 删除
        userRewardRepository.deleteById(id);

        // 验证删除
        assertFalse(userRewardRepository.existsById(id), "删除后应该不存在");
    }

    @Test
    void shouldHandleMultipleRewardTypes() {
        // 创建不同类型的奖励记录
        userRewardRepository.save(createReward(ACTIVITY_ID, USER_1, "invitation_accepted", 100));
        userRewardRepository.save(createReward(ACTIVITY_ID, USER_1, "share", 20));
        userRewardRepository.save(createReward(ACTIVITY_ID, USER_1, "click", 5));
        userRewardRepository.save(createReward(ACTIVITY_ID, USER_1, "bonus", 50));

        // 查询并验证
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(ACTIVITY_ID, USER_1);
        assertEquals(4, rewards.size(), "应该有4条不同类型的奖励记录");

        // 计算总积分
        int totalPoints = rewards.stream().mapToInt(UserRewardEntity::getPoints).sum();
        assertEquals(175, totalPoints, "总积分应该是175");
    }

    @Test
    void shouldHandleZeroAndNegativePoints() {
        // 创建零积分记录
        UserRewardEntity zeroReward = createReward(ACTIVITY_ID, USER_1, "participation", 0);
        userRewardRepository.save(zeroReward);

        // 查询验证
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(ACTIVITY_ID, USER_1);
        assertEquals(1, rewards.size());
        assertEquals(0, rewards.get(0).getPoints());
    }

    @Test
    void shouldSupportMultipleActivitiesPerUser() {
        // 同一用户在不同活动中获得奖励
        userRewardRepository.save(createReward(1L, USER_1, "invite", 50));
        userRewardRepository.save(createReward(2L, USER_1, "share", 30));
        userRewardRepository.save(createReward(3L, USER_1, "click", 10));

        // 分别查询每个活动
        List<UserRewardEntity> activity1Rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(1L, USER_1);
        List<UserRewardEntity> activity2Rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(2L, USER_1);
        List<UserRewardEntity> activity3Rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(3L, USER_1);

        assertEquals(1, activity1Rewards.size());
        assertEquals(1, activity2Rewards.size());
        assertEquals(1, activity3Rewards.size());
    }

    @Test
    void shouldHandleLargeNumberOfRewards() {
        // 批量创建100个奖励记录
        for (int i = 0; i < 100; i++) {
            UserRewardEntity reward = createReward(ACTIVITY_ID, USER_1, "reward_" + i, 10);
            reward.setCreatedAt(now.minusMinutes(i));
            userRewardRepository.save(reward);
        }

        // 查询并验证
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(ACTIVITY_ID, USER_1);
        assertEquals(100, rewards.size(), "应该返回100条记录");

        // 验证总积分
        int totalPoints = rewards.stream().mapToInt(UserRewardEntity::getPoints).sum();
        assertEquals(1000, totalPoints, "总积分应该是1000");
    }

    @Test
    void shouldHandleSameUserSameActivityMultipleRewards() {
        // 同一用户在同一个活动中获得多次奖励
        for (int i = 0; i < 5; i++) {
            UserRewardEntity reward = createReward(ACTIVITY_ID, USER_1, "invite", 10);
            reward.setCreatedAt(now.minusMinutes(i));
            userRewardRepository.save(reward);
        }

        // 查询验证
        List<UserRewardEntity> rewards = userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(ACTIVITY_ID, USER_1);
        assertEquals(5, rewards.size(), "同一用户同一活动应该有5条奖励记录");
    }

    @Test
    void shouldPreserveAllFields() {
        // 创建完整记录
        UserRewardEntity reward = new UserRewardEntity();
        reward.setActivityId(ACTIVITY_ID);
        reward.setUserId(USER_1);
        reward.setType("special_bonus");
        reward.setPoints(999);
        reward.setCreatedAt(now);

        UserRewardEntity saved = userRewardRepository.save(reward);

        // 查询并验证所有字段
        UserRewardEntity found = userRewardRepository.findById(saved.getId()).orElseThrow();
        assertEquals(ACTIVITY_ID, found.getActivityId());
        assertEquals(USER_1, found.getUserId());
        assertEquals("special_bonus", found.getType());
        assertEquals(999, found.getPoints());
        assertNotNull(found.getCreatedAt());
    }

    /**
     * 辅助方法：创建奖励实体
     */
    private UserRewardEntity createReward(Long activityId, Long userId, String type, int points) {
        UserRewardEntity reward = new UserRewardEntity();
        reward.setActivityId(activityId);
        reward.setUserId(userId);
        reward.setType(type);
        reward.setPoints(points);
        reward.setCreatedAt(now);
        return reward;
    }
}
