package livestream

import (
	"encoding/json"
	"testing"

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

// TestDiscreteRandomDistribution 测试随机离散分布的均匀性
func TestDiscreteRandomDistribution(t *testing.T) {
	// 模拟实际奖品配置
	jsonData := `[{"id":58,"name":"Nu高达","weight":100},{"id":59,"name":"NT高达","weight":100},{"id":60,"name":"魔礼青","weight":100},{"id":61,"name":"维达尔","weight":100},{"id":62,"name":"玉衡星6号","weight":400},{"id":63,"name":"马克兔","weight":600},{"id":64,"name":"00高达","weight":700},{"id":65,"name":"SD随机款","weight":1100},{"id":66,"name":"兰博基尼","weight":3000},{"id":67,"name":"高达徽章","weight":28000},{"id":68,"name":"冰箱贴","weight":65800}]`

	var prizes []*model.LivestreamPrizes
	if err := json.Unmarshal([]byte(jsonData), &prizes); err != nil {
		t.Fatalf("解析奖品数据失败: %v", err)
	}

	// 计算总权重
	var totalWeight int32
	for _, p := range prizes {
		totalWeight += p.Weight
	}

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

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

	// 模拟10000次抽奖
	simulateCount := 10000
	results := make(map[int64]int)

	for i := 0; i < simulateCount; i++ {
		// 模拟随机值
		randValue := int32(i % int(totalWeight)) // 简化为顺序遍历，实际用crypto/rand

		// 查找对应的奖品
		for prizeID, positions := range state.PrizePosMap {
			for _, pos := range positions {
				if pos == randValue {
					results[prizeID]++
					break
				}
			}
		}
	}

	// 创建奖品ID到名称的映射
	prizeMap := make(map[int64]string)
	for _, p := range prizes {
		prizeMap[p.ID] = p.Name
	}

	// 输出统计结果
	t.Log("\n========== 随机离散分布测试结果 ==========")
	for _, p := range prizes {
		count := results[p.ID]
		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)
	}
}

// TestContinuousVsDiscrete 对比连续区间和随机离散
func TestContinuousVsDiscrete(t *testing.T) {
	// 简化奖品配置
	prizes := []*model.LivestreamPrizes{
		{ID: 1, Name: "大奖", Weight: 100},
		{ID: 2, Name: "小奖A", Weight: 3000},
		{ID: 3, Name: "小奖B", Weight: 3000},
		{ID: 4, Name: "冰箱贴", Weight: 65800},
	}

	totalWeight := int32(100 + 3000 + 3000 + 65800)

	t.Logf("\n========== 连续区间 vs 随机离散对比 ==========")
	t.Logf("总权重: %d", totalWeight)
	t.Log("")

	// 连续区间模拟
	t.Log("【连续区间方法】")
	t.Log("大奖区间: [0, 99] (0.1%)")
	t.Log("小奖A区间: [100, 3099] (3%)")
	t.Log("小奖B区间: [3100, 6099] (3%)")
	t.Log("冰箱贴区间: [6100, 71899] (65.8%)")
	t.Log("")

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

	t.Log("【随机离散方法】")
	t.Logf("大奖的随机位置数: %d", len(state.PrizePosMap[1]))
	t.Logf("小奖A的随机位置数: %d", len(state.PrizePosMap[2]))
	t.Logf("小奖B的随机位置数: %d", len(state.PrizePosMap[3]))
	t.Logf("冰箱贴的随机位置数: %d", len(state.PrizePosMap[4]))

	// 验证位置分布
	t.Log("\n位置分布示例（前10个）:")
	if positions, ok := state.PrizePosMap[1]; ok && len(positions) > 0 {
		sampleSize := 10
		if len(positions) < sampleSize {
			sampleSize = len(positions)
		}
		t.Logf("大奖位置: %v", positions[:sampleSize])
	}

	if positions, ok := state.PrizePosMap[4]; ok && len(positions) > 0 {
		sampleSize := 10
		if len(positions) < sampleSize {
			sampleSize = len(positions)
		}
		t.Logf("冰箱贴位置: %v", positions[:sampleSize])
	}
}

// TestEdgeCases 测试边界情况
func TestEdgeCases(t *testing.T) {
	t.Run("空奖品列表", func(t *testing.T) {
		_, err := GenerateDiscretePositions(1, []*model.LivestreamPrizes{})
		if err == nil {
			t.Error("应该返回错误")
		}
	})

	t.Run("零权重", func(t *testing.T) {
		prizes := []*model.LivestreamPrizes{
			{ID: 1, Name: "奖品", Weight: 0},
		}
		_, err := GenerateDiscretePositions(1, prizes)
		if err == nil {
			t.Error("应该返回错误")
		}
	})

	t.Run("单个奖品", func(t *testing.T) {
		prizes := []*model.LivestreamPrizes{
			{ID: 1, Name: "唯一奖品", Weight: 1000},
		}
		state, err := GenerateDiscretePositions(1, prizes)
		if err != nil {
			t.Fatalf("不应该出错: %v", err)
		}
		if len(state.PrizePosMap[1]) != 1000 {
			t.Errorf("位置数量错误，期望1000，实际%d", len(state.PrizePosMap[1]))
		}
	})
}

// TestPositionUniqueness 测试位置的唯一性
func TestPositionUniqueness(t *testing.T) {
	prizes := []*model.LivestreamPrizes{
		{ID: 1, Name: "大奖", Weight: 100},
		{ID: 2, Name: "小奖", Weight: 3000},
		{ID: 3, Name: "冰箱贴", Weight: 65800},
	}

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

	// 收集所有位置
	allPositions := make(map[int32]int64)
	for prizeID, positions := range state.PrizePosMap {
		for _, pos := range positions {
			if existingPrizeID, exists := allPositions[pos]; exists {
				t.Errorf("位置 %d 被多个奖品占用: 奖品%d 和 奖品%d", pos, existingPrizeID, prizeID)
			}
			allPositions[pos] = prizeID
		}
	}

	expectedCount := 100 + 3000 + 65800
	if len(allPositions) != expectedCount {
		t.Errorf("位置总数错误，期望%d，实际%d", expectedCount, len(allPositions))
	}

	t.Logf("位置唯一性验证通过: %d 个唯一位置", len(allPositions))
}

// BenchmarkDiscreteVsContinuous 性能对比测试
func BenchmarkDiscreteGeneration(b *testing.B) {
	prizes := []*model.LivestreamPrizes{
		{ID: 1, Name: "大奖", Weight: 100},
		{ID: 2, Name: "小奖A", Weight: 3000},
		{ID: 3, Name: "小奖B", Weight: 3000},
		{ID: 4, Name: "冰箱贴", Weight: 65800},
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := GenerateDiscretePositions(int64(i), prizes)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// 打印结果辅助函数
func printResults(t *testing.T, results map[int64]int, prizes []*model.LivestreamPrizes, simulateCount int) {
	t.Log("\n========== 测试结果 ==========")
	for _, p := range prizes {
		count := results[p.ID]
		t.Logf("%-20s 中奖次数: %d (%.2f%%)", p.Name, count, float64(count)/float64(simulateCount)*100)
	}
}
