package app

import (
	"bindbox-game/internal/code"
	"bindbox-game/internal/pkg/core"
	"bindbox-game/internal/pkg/util/remark"
	"bindbox-game/internal/pkg/validation"
	"bindbox-game/internal/repository/mysql/model"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"strings"
	"time"
)

type orderResultQuery struct {
	OrderNo string `form:"order_no"`
}

type orderResultItem struct {
	RewardID   int64  `json:"reward_id"`
	RewardName string `json:"reward_name"`
	Level      int32  `json:"level"`
	DrawIndex  int32  `json:"draw_index"`
	Image      string `json:"image"`
}

type orderResultResponse struct {
	Status       string            `json:"status"`
	DrawMode     string            `json:"draw_mode"`
	Count        int64             `json:"count"`
	Completed    int64             `json:"completed"`
	Results      []orderResultItem `json:"results"`
	Receipt      map[string]any    `json:"receipt,omitempty"`
	NextPollMs   int               `json:"nextPollMs"`
	SeedHex      string            `json:"seed_hex,omitempty"`
	NextDrawTime string            `json:"next_draw_time,omitempty"`
}

// LotteryResultByOrder 抽奖订单结果查询
// @Summary 抽奖订单结果查询
// @Description 根据订单号查询抽奖结果与进度，返回结果明细与可验证凭证；需登录
// @Tags APP端.抽奖
// @Accept json
// @Produce json
// @Security LoginVerifyToken
// @Param order_no query string true "订单号"
// @Success 200 {object} orderResultResponse
// @Failure 400 {object} code.Failure
// @Router /api/app/lottery/result [get]
func (h *handler) LotteryResultByOrder() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(orderResultQuery)
		if err := ctx.ShouldBindQuery(req); err != nil || req.OrderNo == "" {
			ctx.AbortWithError(core.Error(400, code.ParamBindError, validation.Error(err)))
			return
		}
		userID := int64(ctx.SessionUserInfo().Id)
		ord, err := h.readDB.Orders.WithContext(ctx.RequestContext()).Where(h.readDB.Orders.OrderNo.Eq(req.OrderNo), h.readDB.Orders.UserID.Eq(userID)).First()
		if err != nil || ord == nil {
			ctx.AbortWithError(core.Error(400, code.ParamBindError, "order not found"))
			return
		}

		rmk := remark.Parse(ord.Remark)
		iss := rmk.IssueID
		dc := rmk.Count

		// 3. 解析活动模式
		mode := "scheduled"
		if iss > 0 {
			issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityIssues.ID.Eq(iss)).First()
			if issue != nil {
				act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(issue.ActivityID)).First()
				if act != nil && act.DrawMode != "" {
					mode = act.DrawMode
				}
			}
		}

		// 4. 执行开奖补齐 (如果尚未全部完成)
		if ord.Status == 2 && mode == "instant" {
			// 直接调用统一开奖服务，它会处理所有缺失的抽奖序号
			_ = h.activity.ProcessOrderLottery(ctx.RequestContext(), ord.ID)
		}

		// 5. 重新获取最新的开奖记录 (包含刚刚可能补齐的内容)
		logs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).
			Where(h.readDB.ActivityDrawLogs.OrderID.Eq(ord.ID)).
			Order(h.readDB.ActivityDrawLogs.DrawIndex).
			Find()

		// 批量预加载所有奖品配置
		rewardIDs := make([]int64, 0, len(logs))
		for _, lg := range logs {
			if lg.RewardID > 0 {
				rewardIDs = append(rewardIDs, lg.RewardID)
			}
		}

		rewardMap := make(map[int64]*model.ActivityRewardSettings)
		if len(rewardIDs) > 0 {
			rwList, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.In(rewardIDs...)).Find()
			for _, rw := range rwList {
				rewardMap[rw.ID] = rw
			}
		}

		// 收集所有需要查询的产品ID（包括开奖记录和翻倍记录）
		productIDs := make([]int64, 0)
		productIDSet := make(map[int64]struct{})

		for _, rw := range rewardMap {
			if rw.ProductID > 0 {
				if _, ok := productIDSet[rw.ProductID]; !ok {
					productIDSet[rw.ProductID] = struct{}{}
					productIDs = append(productIDs, rw.ProductID)
				}
			}
		}

		// 6. 查询道具卡翻倍的奖励（remark包含"倍数"）
		doubledInvs, _ := h.readDB.UserInventory.WithContext(ctx.RequestContext()).
			Where(h.readDB.UserInventory.OrderID.Eq(ord.ID)).
			Find()

		var validDoubledInvs []*model.UserInventory
		for _, inv := range doubledInvs {
			if inv.Remark != "" && strings.Contains(inv.Remark, "(倍数)") {
				validDoubledInvs = append(validDoubledInvs, inv)
				if inv.ProductID > 0 {
					if _, ok := productIDSet[inv.ProductID]; !ok {
						productIDSet[inv.ProductID] = struct{}{}
						productIDs = append(productIDs, inv.ProductID)
					}
				}
			}
		}

		// 批量预加载所有产品信息
		productMap := make(map[int64]*model.Products)
		if len(productIDs) > 0 {
			pList, _ := h.readDB.Products.WithContext(ctx.RequestContext()).Where(h.readDB.Products.ID.In(productIDs...)).Find()
			for _, p := range pList {
				productMap[p.ID] = p
			}
		}

		// 构建结果列表
		completed := int64(len(logs))
		items := make([]orderResultItem, 0, len(logs)+len(validDoubledInvs))
		drawLogIDs := make([]int64, 0, len(logs))

		// 处理普通奖励
		for _, lg := range logs {
			drawLogIDs = append(drawLogIDs, lg.ID)
			image := ""
			name := ""
			if rw, ok := rewardMap[lg.RewardID]; ok {
				if p, ok := productMap[rw.ProductID]; ok {
					name = p.Name
					if p.ImagesJSON != "" {
						var imgs []string
						if json.Unmarshal([]byte(p.ImagesJSON), &imgs) == nil && len(imgs) > 0 {
							image = imgs[0]
						}
					}
				}
			}

			items = append(items, orderResultItem{
				RewardID:   lg.RewardID,
				RewardName: name,
				Level:      lg.Level,
				DrawIndex:  int32(lg.DrawIndex + 1),
				Image:      image,
			})
		}

		// 处理翻倍奖励
		for _, inv := range validDoubledInvs {
			image := ""
			name := inv.Remark
			if p, ok := productMap[inv.ProductID]; ok {
				name = p.Name
				if p.ImagesJSON != "" {
					var imgs []string
					if json.Unmarshal([]byte(p.ImagesJSON), &imgs) == nil && len(imgs) > 0 {
						image = imgs[0]
					}
				}
			}

			items = append(items, orderResultItem{
				RewardID:   inv.RewardID,
				RewardName: name + "(翻倍)",
				Level:      0,
				DrawIndex:  int32(len(logs) + 1), // 翻倍奖励排在最后
				Image:      image,
			})
		}

		st := "pending"
		if ord.Status == 4 {
			st = "refunded"
		} else if ord.Status == 2 {
			if completed < dc {
				st = "paid_waiting"
			} else {
				st = "settled"
			}
		}

		var receipt map[string]any
		var randomReceipts []map[string]any
		if len(drawLogIDs) > 0 {
			if recs, _ := h.readDB.ActivityDrawReceipts.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawReceipts.DrawLogID.In(drawLogIDs...)).Find(); len(recs) > 0 {
				recMap := make(map[int64]*model.ActivityDrawReceipts, len(recs))
				for _, r := range recs {
					recMap[r.DrawLogID] = r
				}
				randomReceipts = make([]map[string]any, 0, len(recs))
				for i := 0; i < len(logs); i++ {
					lg := logs[i]
					if r, ok := recMap[lg.ID]; ok {
						randomReceipts = append(randomReceipts, map[string]any{
							"draw_log_id":      lg.ID,
							"reward_id":        lg.RewardID,
							"draw_index":       i + 1,
							"algo_version":     r.AlgoVersion,
							"round_id":         r.RoundID,
							"draw_id":          r.DrawID,
							"client_id":        r.ClientID,
							"timestamp":        r.Timestamp,
							"server_seed_hash": r.ServerSeedHash,
							"server_sub_seed":  r.ServerSubSeed,
							"client_seed":      r.ClientSeed,
							"nonce":            r.Nonce,
							"items_root":       r.ItemsRoot,
							"weights_total":    r.WeightsTotal,
							"selected_index":   r.SelectedIndex,
							"rand_proof":       r.RandProof,
							"signature":        r.Signature,
							"items_snapshot":   r.ItemsSnapshot,
						})
					}
				}
			}
		}
		aid := int64(0)
		if iss > 0 {
			issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityIssues.ID.Eq(iss)).First()
			if issue != nil {
				aid = issue.ActivityID
			}
		}
		if aid > 0 {
			act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(aid)).First()
			if act != nil && len(act.CommitmentSeedMaster) > 0 {
				ts := time.Now().UnixMilli()
				nonce := ts
				mac := hmac.New(sha256.New, act.CommitmentSeedMaster)
				mac.Write([]byte(h.joinSigPayload(userID, iss, ts, nonce)))
				sig := base64.StdEncoding.EncodeToString(mac.Sum(nil))
				receipt = map[string]any{
					"issue_id":     iss,
					"seed_version": act.CommitmentStateVersion,
					"timestamp":    ts,
					"nonce":        nonce,
					"signature":    sig,
					"algorithm":    "HMAC-SHA256",
					"inputs":       map[string]any{"user_id": userID, "issue_id": iss, "order_id": ord.ID, "timestamp": ts, "nonce": nonce},
				}
			}
		}
		if len(randomReceipts) > 0 {
			if receipt == nil {
				receipt = map[string]any{}
			}
			receipt["draw_receipts"] = randomReceipts
		}
		// 构建响应，包含随机种子和下次开奖时间
		var seedHex string
		var nextDrawTime string
		if aid > 0 {
			act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(aid)).First()
			if act != nil {
				// 问题2: 返回随机种子（十六进制格式）
				if len(act.CommitmentSeedMaster) > 0 {
					seedHex = hex.EncodeToString(act.CommitmentSeedMaster)
				}
				// 问题3: 定时抽奖返回下一次开奖时间
				if mode == "scheduled" && !act.ScheduledTime.IsZero() {
					nextDrawTime = act.ScheduledTime.Format(time.RFC3339)
				}
			}
		}
		rsp := &orderResultResponse{Status: st, DrawMode: mode, Count: dc, Completed: completed, Results: items, Receipt: receipt, NextPollMs: 2000, SeedHex: seedHex, NextDrawTime: nextDrawTime}
		ctx.Payload(rsp)
	}
}
