package livestream

import (
	"testing"

	"bindbox-game/internal/repository/mysql/model"
)

// TestDrawWithDiscreteIntegration 集成测试：完整的随机离散抽奖流程
func TestDrawWithDiscreteIntegration(t *testing.T) {
	// 创建service实例（简化测试，不依赖真实数据库）
	s := &service{
		discreteCache: NewActivityDiscreteCache(),
	}

	// 1. 配置奖品
	prizes := []*model.LivestreamPrizes{
		{ID: 58, Name: "Nu高达", Weight: 100, Remaining: -1},
		{ID: 59, Name: "NT高达", Weight: 100, Remaining: -1},
		{ID: 60, Name: "魔礼青", Weight: 100, Remaining: -1},
		{ID: 61, Name: "维达尔", Weight: 100, Remaining: -1},
		{ID: 62, Name: "玉衡星6号", Weight: 400, Remaining: -1},
		{ID: 63, Name: "马克兔", Weight: 600, Remaining: -1},
		{ID: 64, Name: "00高达", Weight: 700, Remaining: -1},
		{ID: 65, Name: "SD随机款", Weight: 1100, Remaining: -1},
		{ID: 66, Name: "兰博基尼", Weight: 3000, Remaining: -1},
		{ID: 67, Name: "高达徽章", Weight: 28000, Remaining: -1},
		{ID: 68, Name: "冰箱贴", Weight: 65800, Remaining: -1},
	}

	activityID := int64(1)

	// 2. 生成随机离散位置
	state, err := GenerateDiscretePositions(activityID, prizes)
	if err != nil {
		t.Fatalf("生成随机离散位置失败: %v", err)
	}

	// 3. 设置到缓存
	s.discreteCache.Set(state)

	t.Logf("总权重: %d", state.TotalWeight)

	// 4. 模拟多次抽奖
	simulateCount := 1000
	results := make(map[int64]int)

	for i := 0; i < simulateCount; i++ {
		// 模拟随机值生成（实际用crypto/rand）
		randValue := int32(i % int(state.TotalWeight))

		// 查找对应的奖品
		prizeMap := make(map[int64]*model.LivestreamPrizes)
		for _, p := range prizes {
			prizeMap[p.ID] = p
		}

		// 二分查找
		found := false
		for prizeID, positions := range state.PrizePosMap {
			for _, pos := range positions {
				if pos == randValue {
					results[prizeID]++
					found = true
					break
				}
			}
			if found {
				break
			}
		}
	}

	// 5. 统计结果
	t.Log("\n========== 随机离散抽奖统计结果 ==========")
	t.Logf("模拟次数: %d", simulateCount)
	t.Log("")

	totalWeight := int32(0)
	for _, p := range prizes {
		totalWeight += p.Weight
	}

	totalCount := 0
	for _, p := range prizes {
		count := results[p.ID]
		totalCount += count
		theoryProb := float64(p.Weight) / float64(totalWeight) * 100
		actualProb := float64(count) / float64(simulateCount) * 100
		diff := actualProb - theoryProb

		t.Logf("%-20s 权重:%6d 理论:%6.2f%% 实际:%6.2f%% 偏差:%+6.2f%% 次数:%5d",
			p.Name, p.Weight, theoryProb, actualProb, diff, count)
	}

	t.Logf("\n总计中奖: %d", totalCount)

	// 6. 验证概率偏差（允许的误差范围：±2%）
	t.Run("概率偏差检查", func(t *testing.T) {
		for _, p := range prizes {
			count := results[p.ID]
			theoryProb := float64(p.Weight) / float64(totalWeight) * 100
			actualProb := float64(count) / float64(simulateCount) * 100
			diff := actualProb - theoryProb

			// 大奖（权重100）允许更大偏差
			threshold := 2.0
			if p.Weight <= 100 {
				threshold = 5.0 // 大奖允许5%偏差
			}

			if diff > threshold || diff < -threshold {
				t.Errorf("%s 概率偏差过大: 理论%.2f%% 实际%.2f%% 偏差%.2f%% (阈值±%.1f%%)",
					p.Name, theoryProb, actualProb, diff, threshold)
			}
		}
	})
}

// TestDrawVsOriginal 对比新旧方案
func TestDrawVsOriginal(t *testing.T) {
	prizes := []*model.LivestreamPrizes{
		{ID: 1, Name: "大奖", Weight: 100, Remaining: -1},
		{ID: 2, Name: "中奖", Weight: 3000, Remaining: -1},
		{ID: 3, Name: "小奖", Weight: 3000, Remaining: -1},
		{ID: 4, Name: "冰箱贴", Weight: 65800, Remaining: -1},
	}

	activityID := int64(999)

	// 原始连续区间方案
	t.Log("\n========== 方案对比 ==========")
	t.Log("【原始连续区间方案】")
	t.Log("大奖区间: [0, 99] (0.15%)")
	t.Log("中奖区间: [100, 3099] (4.48%)")
	t.Log("小奖区间: [3100, 6099] (4.48%)")
	t.Log("冰箱贴区间: [6100, 71899] (97.02%)")
	t.Log("")

	// 随机离散方案
	state, err := GenerateDiscretePositions(activityID, prizes)
	if err != nil {
		t.Fatalf("生成失败: %v", err)
	}

	t.Log("【随机离散方案】")
	for _, p := range prizes {
		positions := state.PrizePosMap[p.ID]
		t.Logf("%s: %d个随机位置", p.Name, len(positions))
	}

	// 位置分布示例
	t.Log("\n【位置分布示例】")
	if pos, ok := state.PrizePosMap[1]; ok && len(pos) > 0 {
		sample := make([]int32, 0, 10)
		for i := 0; i < 10 && i < len(pos); i++ {
			sample = append(sample, pos[i])
		}
		t.Logf("大奖前10个位置: %v", sample)
	}
	if pos, ok := state.PrizePosMap[4]; ok && len(pos) > 0 {
		sample := make([]int32, 0, 10)
		for i := 0; i < 10 && i < len(pos); i++ {
			sample = append(sample, pos[i])
		}
		t.Logf("冰箱贴前10个位置: %v", sample)
	}
}

// TestCacheOperations 测试缓存操作
func TestCacheOperations(t *testing.T) {
	cache := NewActivityDiscreteCache()

	// 创建测试状态
	state := &ActivityDiscreteState{
		ActivityID:  1,
		TotalWeight: 1000,
		PrizePosMap: map[int64][]int32{
			1: {0, 10, 20, 30, 40},
			2: {5, 15, 25, 35, 45},
		},
	}

	// 测试Set
	cache.Set(state)

	// 测试Get
	got, ok := cache.Get(1)
	if !ok {
		t.Fatal("应该能找到缓存")
	}
	if got.ActivityID != 1 {
		t.Errorf("ActivityID不匹配: 期望1, 实际%d", got.ActivityID)
	}

	// 测试Delete
	cache.Delete(1)
	_, ok = cache.Get(1)
	if ok {
		t.Error("删除后应该找不到")
	}

	t.Log("缓存操作测试通过")
}

// TestSelectPrizeByDiscreteWithList 测试带奖品列表的选择
func TestSelectPrizeByDiscreteWithList(t *testing.T) {
	prizes := []*model.LivestreamPrizes{
		{ID: 1, Name: "大奖", Weight: 100, Remaining: -1},
		{ID: 2, Name: "小奖", Weight: 3000, Remaining: -1},
	}

	state, err := GenerateDiscretePositions(1, prizes)
	if err != nil {
		t.Fatalf("生成失败: %v", err)
	}

	// 测试有效随机值
	for randValue := int32(0); randValue < state.TotalWeight; randValue++ {
		prize, _, err := SelectPrizeByDiscreteWithList(state, prizes, randValue)
		if err != nil {
			t.Errorf("随机值%d查找失败: %v", randValue, err)
			continue
		}
		if prize == nil {
			t.Errorf("随机值%d返回空奖品", randValue)
			continue
		}
	}

	// 测试边界值
	t.Run("边界值测试", func(t *testing.T) {
		// 超出范围
		_, _, err := SelectPrizeByDiscreteWithList(state, prizes, state.TotalWeight)
		if err == nil {
			t.Error("超出范围应该返回错误")
		}
	})

	t.Logf("成功测试了 %d 个随机值", state.TotalWeight)
}
