package com.mosquito.project.persistence.entity;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;

@DisplayName("ActivityRewardEntity 测试")
class ActivityRewardEntityTest {

    @Test
    @DisplayName("id setter/getter 应该正常工作")
    void shouldHandleId_whenUsingGetterAndSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        Long id = 12345L;

        // When
        entity.setId(id);

        // Then
        assertThat(entity.getId()).isEqualTo(id);
    }

    @Test
    @DisplayName("id 应该处理null值")
    void shouldHandleNullId_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setId(null);

        // Then
        assertThat(entity.getId()).isNull();
    }

    @Test
    @DisplayName("activityId setter/getter 应该正常工作")
    void shouldHandleActivityId_whenUsingGetterAndSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        Long activityId = 100L;

        // When
        entity.setActivityId(activityId);

        // Then
        assertThat(entity.getActivityId()).isEqualTo(activityId);
    }

    @Test
    @DisplayName("activityId 应该处理null值")
    void shouldHandleNullActivityId_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setActivityId(null);

        // Then
        assertThat(entity.getActivityId()).isNull();
    }

    @ParameterizedTest
    @ValueSource(ints = {1, 5, 10, 50, 100, 1000, Integer.MAX_VALUE})
    @DisplayName("inviteThreshold 应该接受各种正整数值")
    void shouldAcceptVariousThresholds_whenUsingSetter(int threshold) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setInviteThreshold(threshold);

        // Then
        assertThat(entity.getInviteThreshold()).isEqualTo(threshold);
    }

    @Test
    @DisplayName("inviteThreshold 应该处理null值")
    void shouldHandleNullInviteThreshold_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setInviteThreshold(null);

        // Then
        assertThat(entity.getInviteThreshold()).isNull();
    }

    @ParameterizedTest
    @ValueSource(ints = {0, -1, -100})
    @DisplayName("inviteThreshold 应该接受零和负值（业务层验证）")
    void shouldAcceptZeroAndNegativeThresholds(int threshold) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When & Then - 实体层允许任何Integer值，业务逻辑层负责验证
        assertThatNoException().isThrownBy(() -> entity.setInviteThreshold(threshold));
        assertThat(entity.getInviteThreshold()).isEqualTo(threshold);
    }

    @ParameterizedTest
    @ValueSource(strings = {"POINTS", "COUPON", "PHYSICAL", "VIRTUAL", "CASH", "VIP", "DISCOUNT"})
    @NullAndEmptySource
    @DisplayName("rewardType 应该接受各种奖励类型")
    void shouldAcceptVariousRewardTypes_whenUsingSetter(String rewardType) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When & Then
        assertThatNoException().isThrownBy(() -> entity.setRewardType(rewardType));
        assertThat(entity.getRewardType()).isEqualTo(rewardType);
    }

    @Test
    @DisplayName("rewardType 应该处理最大长度字符串")
    void shouldHandleMaxLengthRewardType_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        String maxLengthType = "T".repeat(50);

        // When
        entity.setRewardType(maxLengthType);

        // Then
        assertThat(entity.getRewardType()).hasSize(50);
    }

    @ParameterizedTest
    @ValueSource(strings = {
        "100",
        "{\"amount\": 100, \"currency\": \"CNY\"}",
        "COUPON_CODE_12345",
        "product_id:12345;quantity:1",
        "https://example.com/reward/claim"
    })
    @NullAndEmptySource
    @DisplayName("rewardValue 应该接受各种格式的奖励值")
    void shouldAcceptVariousRewardValues_whenUsingSetter(String rewardValue) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When & Then
        assertThatNoException().isThrownBy(() -> entity.setRewardValue(rewardValue));
        assertThat(entity.getRewardValue()).isEqualTo(rewardValue);
    }

    @Test
    @DisplayName("rewardValue 应该处理最大长度字符串")
    void shouldHandleMaxLengthRewardValue_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        String maxLengthValue = "V".repeat(255);

        // When
        entity.setRewardValue(maxLengthValue);

        // Then
        assertThat(entity.getRewardValue()).hasSize(255);
    }

    @Test
    @DisplayName("skipValidation 默认为false")
    void shouldDefaultToFalse_whenEntityIsNew() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // Then
        assertThat(entity.getSkipValidation()).isFalse();
    }

    @Test
    @DisplayName("skipValidation setter应该能够设置为true")
    void shouldSetSkipValidationToTrue_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setSkipValidation(true);

        // Then
        assertThat(entity.getSkipValidation()).isTrue();
    }

    @Test
    @DisplayName("skipValidation setter应该能够设置为false")
    void shouldSetSkipValidationToFalse_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        entity.setSkipValidation(true);

        // When
        entity.setSkipValidation(false);

        // Then
        assertThat(entity.getSkipValidation()).isFalse();
    }

    @Test
    @DisplayName("skipValidation 应该处理null值")
    void shouldHandleNullSkipValidation_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setSkipValidation(null);

        // Then
        assertThat(entity.getSkipValidation()).isNull();
    }

    @Test
    @DisplayName("完整奖励规则实体构建应该正常工作")
    void shouldBuildCompleteRewardEntity_whenSettingAllFields() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setId(1L);
        entity.setActivityId(100L);
        entity.setInviteThreshold(10);
        entity.setRewardType("POINTS");
        entity.setRewardValue("1000");
        entity.setSkipValidation(false);

        // Then
        assertThat(entity.getId()).isEqualTo(1L);
        assertThat(entity.getActivityId()).isEqualTo(100L);
        assertThat(entity.getInviteThreshold()).isEqualTo(10);
        assertThat(entity.getRewardType()).isEqualTo("POINTS");
        assertThat(entity.getRewardValue()).isEqualTo("1000");
        assertThat(entity.getSkipValidation()).isFalse();
    }

    @Test
    @DisplayName("空实体应该所有字段为null或默认值")
    void shouldHaveDefaultValues_whenEntityIsNew() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // Then
        assertThat(entity.getId()).isNull();
        assertThat(entity.getActivityId()).isNull();
        assertThat(entity.getInviteThreshold()).isNull();
        assertThat(entity.getRewardType()).isNull();
        assertThat(entity.getRewardValue()).isNull();
        assertThat(entity.getSkipValidation()).isFalse(); // 默认值为false
    }

    @ParameterizedTest
    @CsvSource({
        "1, 5, POINTS, 100, false",
        "2, 10, COUPON, COUPON2024, false",
        "3, 50, PHYSICAL, gift_box_premium, true",
        "4, 100, VIP, VIP_GOLD_1YEAR, false",
        "5, 1, CASH, 50.00, false"
    })
    @DisplayName("实体应该支持各种奖励规则配置")
    void shouldSupportVariousRewardConfigurations(Long id, int threshold, String type, String value, boolean skipValidation) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setId(id);
        entity.setActivityId(100L);
        entity.setInviteThreshold(threshold);
        entity.setRewardType(type);
        entity.setRewardValue(value);
        entity.setSkipValidation(skipValidation);

        // Then
        assertThat(entity.getId()).isEqualTo(id);
        assertThat(entity.getActivityId()).isEqualTo(100L);
        assertThat(entity.getInviteThreshold()).isEqualTo(threshold);
        assertThat(entity.getRewardType()).isEqualTo(type);
        assertThat(entity.getRewardValue()).isEqualTo(value);
        assertThat(entity.getSkipValidation()).isEqualTo(skipValidation);
    }

    @Test
    @DisplayName("实体应该支持JSON格式的rewardValue")
    void shouldSupportJsonRewardValue_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        String jsonValue = "{\"points\":1000,\"expiresAt\":\"2024-12-31\",\"conditions\":[{\"type\":\"min_order\",\"value\":50}]}";

        // When
        entity.setRewardValue(jsonValue);

        // Then
        assertThat(entity.getRewardValue()).isEqualTo(jsonValue);
        assertThat(entity.getRewardValue()).contains("points");
        assertThat(entity.getRewardValue()).contains("1000");
    }

    @Test
    @DisplayName("实体应该支持URL格式的rewardValue")
    void shouldSupportUrlRewardValue_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        String urlValue = "https://cdn.example.com/rewards/download/abc123.pdf?token=xyz789";

        // When
        entity.setRewardValue(urlValue);

        // Then
        assertThat(entity.getRewardValue()).isEqualTo(urlValue);
        assertThat(entity.getRewardValue()).startsWith("https://");
    }

    @Test
    @DisplayName("实体应该支持多个奖励规则关联到同一活动")
    void shouldAllowMultipleRewardsForSameActivity_whenUsingSetter() {
        // Given
        Long activityId = 100L;

        ActivityRewardEntity reward1 = new ActivityRewardEntity();
        reward1.setActivityId(activityId);
        reward1.setInviteThreshold(5);
        reward1.setRewardType("POINTS");
        reward1.setRewardValue("100");

        ActivityRewardEntity reward2 = new ActivityRewardEntity();
        reward2.setActivityId(activityId);
        reward2.setInviteThreshold(10);
        reward2.setRewardType("COUPON");
        reward2.setRewardValue("SAVE20");

        ActivityRewardEntity reward3 = new ActivityRewardEntity();
        reward3.setActivityId(activityId);
        reward3.setInviteThreshold(50);
        reward3.setRewardType("VIP");
        reward3.setRewardValue("VIP_GOLD");

        // Then
        assertThat(reward1.getActivityId()).isEqualTo(activityId);
        assertThat(reward2.getActivityId()).isEqualTo(activityId);
        assertThat(reward3.getActivityId()).isEqualTo(activityId);
        
        // 验证不同阈值
        assertThat(reward1.getInviteThreshold()).isEqualTo(5);
        assertThat(reward2.getInviteThreshold()).isEqualTo(10);
        assertThat(reward3.getInviteThreshold()).isEqualTo(50);
    }

    @Test
    @DisplayName("skipValidation=true 应该跳过验证流程")
    void shouldIndicateSkipValidation_whenSetToTrue() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        entity.setActivityId(100L);
        entity.setInviteThreshold(1);
        entity.setRewardType("POINTS");
        entity.setRewardValue("10");
        entity.setSkipValidation(true);

        // Then - skipValidation标志表示这个奖励不经过验证流程直接发放
        assertThat(entity.getSkipValidation()).isTrue();
    }

    @ParameterizedTest
    @CsvSource({
        "POINTS, numeric",
        "COUPON, alphanumeric",
        "PHYSICAL, product_code",
        "VIRTUAL, download_url",
        "CASH, decimal",
        "VIP, tier_name"
    })
    @DisplayName("实体应该支持各种奖励类型和值格式组合")
    void shouldSupportRewardTypeValueCombinations(String rewardType, String description) {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setRewardType(rewardType);
        entity.setRewardValue("test_value_" + description);

        // Then
        assertThat(entity.getRewardType()).isEqualTo(rewardType);
        assertThat(entity.getRewardValue()).contains(description);
    }

    @Test
    @DisplayName("边界值：最大inviteThreshold")
    void shouldHandleMaxInviteThreshold_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();
        int maxThreshold = Integer.MAX_VALUE;

        // When
        entity.setInviteThreshold(maxThreshold);

        // Then
        assertThat(entity.getInviteThreshold()).isEqualTo(maxThreshold);
    }

    @Test
    @DisplayName("边界值：零inviteThreshold")
    void shouldHandleZeroInviteThreshold_whenUsingSetter() {
        // Given
        ActivityRewardEntity entity = new ActivityRewardEntity();

        // When
        entity.setInviteThreshold(0);

        // Then
        assertThat(entity.getInviteThreshold()).isZero();
    }

    @Test
    @DisplayName("实体应该与ActivityEntity概念关联")
    void shouldConceptuallyAssociateWithActivity_whenSettingActivityId() {
        // Given
        ActivityRewardEntity reward = new ActivityRewardEntity();
        Long activityId = 999L;

        // When
        reward.setActivityId(activityId);

        // Then
        assertThat(reward.getActivityId()).isEqualTo(activityId);
        // 这里模拟了与ActivityEntity的关联，实际关系由数据库外键维护
    }
}
