package strategy

import (
	"bindbox-game/internal/repository/mysql/dao"
	"context"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"fmt"
)

type ichibanStrategy struct {
	read  *dao.Query
	write *dao.Query
}

func NewIchiban(read *dao.Query, write *dao.Query) ActivityDrawStrategy {
	return &ichibanStrategy{read: read, write: write}
}

func (s *ichibanStrategy) PreChecks(ctx context.Context, activityID int64, issueID int64, userID int64) error {
	return nil
}

func (s *ichibanStrategy) SelectItem(ctx context.Context, activityID int64, issueID int64, userID int64) (int64, map[string]any, error) {
	return 0, nil, errors.New("ichiban strategy requires SelectItemBySlot")
}

func (s *ichibanStrategy) SelectItemBySlot(ctx context.Context, activityID int64, issueID int64, slotIndex int64) (int64, map[string]any, error) {
	act, err := s.read.Activities.WithContext(ctx).Where(s.read.Activities.ID.Eq(activityID)).First()
	if err != nil || act == nil || len(act.CommitmentSeedMaster) == 0 {
		return 0, nil, errors.New("commitment not found")
	}
	rewards, err := s.read.ActivityRewardSettings.WithContext(ctx).ReadDB().Where(s.read.ActivityRewardSettings.IssueID.Eq(issueID)).Order(
		s.read.ActivityRewardSettings.IsBoss.Desc(),
		s.read.ActivityRewardSettings.Level.Asc(),
		s.read.ActivityRewardSettings.Sort.Asc(),
		s.read.ActivityRewardSettings.ID.Asc(),
	).Find()
	if err != nil || len(rewards) == 0 {
		return 0, nil, errors.New("no rewards")
	}
	// 一番赏：每种奖品 = 1个格位，无数量概念
	totalSlots := int64(len(rewards))
	if totalSlots <= 0 {
		return 0, nil, errors.New("no slots")
	}
	if slotIndex < 0 || slotIndex >= totalSlots {
		return 0, nil, errors.New("slot out of range")
	}
	// build list: 每个reward直接对应一个slot
	slots := make([]int64, totalSlots)
	for i, r := range rewards {
		slots[i] = r.ID
	}
	// deterministic shuffle by CommitmentSeedMaster
	seedKey := act.CommitmentSeedMaster

	mac := hmac.New(sha256.New, seedKey)
	for i := int(totalSlots - 1); i > 0; i-- {
		mac.Reset()
		mac.Write([]byte(fmt.Sprintf("shuffle:%d|issue:%d", i, issueID)))
		sum := mac.Sum(nil)
		rnd := int(binary.BigEndian.Uint64(sum[:8]) % uint64(i+1))
		slots[i], slots[rnd] = slots[rnd], slots[i]
	}
	picked := slots[slotIndex]

	// Calculate seed hash for proof
	sha := sha256.Sum256(seedKey)
	seedHash := fmt.Sprintf("%x", sha)

	proof := map[string]any{
		"total_slots": totalSlots,
		"slot_index":  slotIndex,
		"seed_hash":   seedHash,
		"seed_type":   "commitment",
	}
	return picked, proof, nil
}

func (s *ichibanStrategy) GrantReward(ctx context.Context, userID int64, rewardID int64) error {
	// 一番赏模式下不再需要扣减数量，因为每个奖品对应唯一格位
	// 格位占用通过 issue_position_claims 表来追踪，而非 quantity 字段
	// 这里保留接口兼容性，实际的占用检查在调用方完成
	return nil
}

func (s *ichibanStrategy) PostEffects(ctx context.Context, userID int64, activityID int64, issueID int64, rewardID int64) error {
	return nil
}
