package strategy

import (
	"bindbox-game/internal/repository/mysql/dao"
	"bindbox-game/internal/repository/mysql/model"
	"context"
	"encoding/json"
	"fmt"
	"time"
)

type ActivityDrawStrategy interface {
	PreChecks(ctx context.Context, activityID int64, issueID int64, userID int64) error
	SelectItem(ctx context.Context, activityID int64, issueID int64, userID int64) (int64, map[string]any, error)
	SelectItemBySlot(ctx context.Context, activityID int64, issueID int64, slotIndex int64) (int64, map[string]any, error)
	GrantReward(ctx context.Context, userID int64, rewardID int64) error
	PostEffects(ctx context.Context, userID int64, activityID int64, issueID int64, rewardID int64) error
}

// SaveDrawReceipt 保存抽奖凭据（用户可验证信息）
// drawLogID: ActivityDrawLogs 记录的 ID
// issueID: 期ID
// userID: 用户ID
// proof: SelectItem 返回的 proof map
// w: 写库 dao.Query
func SaveDrawReceipt(ctx context.Context, w *dao.Query, drawLogID int64, issueID int64, userID int64, proof map[string]any) error {
	if proof == nil || drawLogID <= 0 {
		return nil
	}

	// 从 proof 中提取数据
	seedHash := ""
	if v, ok := proof["seed_hash"].(string); ok {
		seedHash = v
	}
	weightsTotal := int64(0)
	if v, ok := proof["weights_total"].(int64); ok {
		weightsTotal = v
	}
	randVal := int64(0)
	if v, ok := proof["rand"].(int64); ok {
		randVal = v
	}
	slotIndex := int32(-1)
	if v, ok := proof["slot_index"].(int64); ok {
		slotIndex = int32(v)
	}
	totalSlots := int64(0)
	if v, ok := proof["total_slots"].(int64); ok {
		totalSlots = v
		weightsTotal = totalSlots // 一番赏用 total_slots 替代 weights_total
	}

	// 序列化 proof 作为 items_snapshot
	proofJSON, _ := json.Marshal(proof)

	receipt := &model.ActivityDrawReceipts{
		CreatedAt:      time.Now(),
		DrawLogID:      drawLogID,
		AlgoVersion:    "HMAC-SHA256-v1",
		RoundID:        issueID,
		DrawID:         drawLogID,
		ClientID:       userID,
		Timestamp:      time.Now().UnixMilli(),
		ServerSeedHash: seedHash,
		ServerSubSeed:  "",
		ClientSeed:     "",
		Nonce:          time.Now().UnixNano(),
		ItemsRoot:      "",
		WeightsTotal:   weightsTotal,
		SelectedIndex:  slotIndex,
		RandProof:      fmt.Sprintf("%x", randVal),
		Signature:      "",
		ItemsSnapshot:  string(proofJSON),
	}

	return w.ActivityDrawReceipts.WithContext(ctx).Create(receipt)
}
