package livestream

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"sort"
	"sync"
	"time"

	"bindbox-game/internal/repository/mysql/model"
	"go.uber.org/zap"
)

// ActivityDiscreteState 活动随机离散状态
type ActivityDiscreteState struct {
	ActivityID    int64
	TotalWeight   int32
	PrizePosMap   map[int64][]int32 // prize_id -> sorted random positions
	LastDrawIndex int32             // 已抽奖序号，用于恢复或验证
	GeneratedAt   time.Time
}

// ActivityDiscreteCache 活动随机离散缓存
type ActivityDiscreteCache struct {
	mu    sync.RWMutex
	cache map[int64]*ActivityDiscreteState
}

// NewActivityDiscreteCache 创建新的缓存实例
func NewActivityDiscreteCache() *ActivityDiscreteCache {
	return &ActivityDiscreteCache{
		cache: make(map[int64]*ActivityDiscreteState),
	}
}

// Get 获取活动的离散状态
func (c *ActivityDiscreteCache) Get(activityID int64) (*ActivityDiscreteState, bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	state, ok := c.cache[activityID]
	return state, ok
}

// Set 设置活动的离散状态
func (c *ActivityDiscreteCache) Set(state *ActivityDiscreteState) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.cache[state.ActivityID] = state
}

// Delete 删除活动的离散状态
func (c *ActivityDiscreteCache) Delete(activityID int64) {
	c.mu.Lock()
	defer c.mu.Unlock()
	delete(c.cache, activityID)
}

// GenerateDiscretePositions 为活动生成随机离散位置
// 调用时机：活动奖品配置完成后调用一次
func GenerateDiscretePositions(activityID int64, prizes []*model.LivestreamPrizes) (*ActivityDiscreteState, error) {
	if len(prizes) == 0 {
		return nil, fmt.Errorf("没有奖品")
	}

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

	if totalWeight == 0 {
		return nil, fmt.Errorf("总权重为0")
	}

	// 创建位置池 [0, totalWeight-1]
	positions := make([]int32, totalWeight)
	for i := int32(0); i < totalWeight; i++ {
		positions[i] = i
	}

	// Fisher-Yates 洗牌（使用 crypto/rand 保证密码学安全）
	for i := totalWeight - 1; i > 0; i-- {
		randBig, err := rand.Int(rand.Reader, big.NewInt(int64(i+1)))
		if err != nil {
			return nil, fmt.Errorf("随机数生成失败: %w", err)
		}
		j := int32(randBig.Int64())
		positions[i], positions[j] = positions[j], positions[i]
	}

	// 分配位置给每个奖品
	prizePosMap := make(map[int64][]int32)
	posIdx := int32(0)

	for _, p := range prizes {
		prizePositions := make([]int32, p.Weight)
		for i := int32(0); i < p.Weight; i++ {
			prizePositions[i] = positions[posIdx]
			posIdx++
		}

		// 必须排序，用于后续二分查找
		sort.Slice(prizePositions, func(i, j int) bool {
			return prizePositions[i] < prizePositions[j]
		})

		prizePosMap[p.ID] = prizePositions
	}

	state := &ActivityDiscreteState{
		ActivityID:    activityID,
		TotalWeight:   totalWeight,
		PrizePosMap:   prizePosMap,
		LastDrawIndex: 0,
		GeneratedAt:   time.Now(),
	}

	return state, nil
}

// SelectPrizeByDiscrete 使用随机离散位置选择奖品
func SelectPrizeByDiscrete(state *ActivityDiscreteState, randValue int32) (*model.LivestreamPrizes, int32, error) {
	if randValue >= state.TotalWeight {
		return nil, 0, fmt.Errorf("随机值超出范围")
	}

	// 二分查找随机值属于哪个奖品的区间
	var selectedPrizeID int64

	for prizeID, positions := range state.PrizePosMap {
		// 二分查找
		idx := sort.Search(len(positions), func(i int) bool {
			return positions[i] >= randValue
		})

		if idx < len(positions) && positions[idx] == randValue {
			selectedPrizeID = prizeID
			break
		}
	}

	if selectedPrizeID == 0 {
		// 如果没找到，这是不应该发生的
		return nil, randValue, fmt.Errorf("未找到匹配的奖品")
	}

	// 找到对应的奖品信息
	// 注意：这里需要从原始奖品列表中查找
	return nil, randValue, fmt.Errorf("需要传递奖品列表进行查找")
}

// SelectPrizeByDiscreteWithList 使用随机离散位置选择奖品（带完整奖品列表）
func SelectPrizeByDiscreteWithList(state *ActivityDiscreteState, prizes []*model.LivestreamPrizes, randValue int32) (*model.LivestreamPrizes, int32, error) {
	if randValue >= state.TotalWeight {
		return nil, 0, fmt.Errorf("随机值超出范围")
	}

	// 创建奖品ID到对象的映射
	prizeMap := make(map[int64]*model.LivestreamPrizes)
	for _, p := range prizes {
		prizeMap[p.ID] = p
	}

	// 查找随机值对应的奖品
	for prizeID, positions := range state.PrizePosMap {
		idx := sort.Search(len(positions), func(i int) bool {
			return positions[i] >= randValue
		})

		if idx < len(positions) && positions[idx] == randValue {
			if prize, ok := prizeMap[prizeID]; ok {
				return prize, randValue, nil
			}
			return nil, randValue, fmt.Errorf("奖品ID %d 不在当前列表中", prizeID)
		}
	}

	return nil, randValue, fmt.Errorf("随机值 %d 未匹配任何奖品", randValue)
}

// LogDrawEvent 记录抽奖事件（用于调试和分析）
func LogDrawEvent(s *service, activityID int64, drawIndex int32, prizeID int64, prizeName string, randValue int32, method string) {
	s.logger.Debug("随机离散抽奖",
		zap.Int64("activity_id", activityID),
		zap.Int32("draw_index", drawIndex),
		zap.Int64("prize_id", prizeID),
		zap.String("prize_name", prizeName),
		zap.Int32("rand_value", randValue),
		zap.String("method", method),
	)
}
