package user

import (
	"context"
	"strings"

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

// DrawReceiptInfo 抽奖验证凭据信息
type DrawReceiptInfo struct {
	DrawLogID      int64  `json:"draw_log_id"`
	RewardID       int64  `json:"reward_id,omitempty"`
	DrawIndex      int    `json:"draw_index"`
	AlgoVersion    string `json:"algo_version"`
	RoundID        int64  `json:"round_id"`
	DrawID         int64  `json:"draw_id"`
	ClientID       int64  `json:"client_id"`
	Timestamp      int64  `json:"timestamp"`
	ServerSeedHash string `json:"server_seed_hash"`
	ServerSubSeed  string `json:"server_sub_seed"`
	ClientSeed     string `json:"client_seed"`
	Nonce          int64  `json:"nonce"`
	ItemsRoot      string `json:"items_root"`
	WeightsTotal   int64  `json:"weights_total"`
	SelectedIndex  int32  `json:"selected_index"`
	RandProof      string `json:"rand_proof"`
	Signature      string `json:"signature,omitempty"`
	ItemsSnapshot  string `json:"items_snapshot,omitempty"`
}

// OrderWithItems 包含订单项的订单信息
type OrderWithItems struct {
	*model.Orders
	Items        []*model.OrderItems `json:"items"`
	ActivityName string              `json:"activity_name"`
	ActivityID   int64               `json:"activity_id,omitempty"`
	PlayType     string              `json:"play_type,omitempty"`
	CategoryID   int64               `json:"category_id,omitempty"`
	CategoryName string              `json:"category_name,omitempty"`
	IssueNumber  string              `json:"issue_number"`
	IsDraw       bool                `json:"is_draw"`
	IsWinner     bool                `json:"is_winner"`
	RewardLevel  int32               `json:"reward_level"`
	DrawReceipts []*DrawReceiptInfo  `json:"draw_receipts"`
	CouponInfo   *CouponSimpleInfo   `json:"coupon_info,omitempty"`
	ItemCardInfo *ItemCardSimpleInfo `json:"item_card_info,omitempty"`
}

type CouponSimpleInfo struct {
	UserCouponID int64  `json:"user_coupon_id"`
	Name         string `json:"name"`
	Type         int32  `json:"type"` // 1:满减 2:折扣
	Value        int64  `json:"value"`
}

type ItemCardSimpleInfo struct {
	UserCardID int64  `json:"user_card_id"`
	Name       string `json:"name"`
	EffectType int32  `json:"effect_type"`
}

func (s *service) ListOrders(ctx context.Context, userID int64, page, pageSize int) (items []*model.Orders, total int64, err error) {
	// 查询用户的所有订单，包括商城直购(1)、抽奖票据(2)和系统发放(3)
	q := s.readDB.Orders.WithContext(ctx).ReadDB().Where(s.readDB.Orders.UserID.Eq(userID))
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	items, err = q.Order(s.readDB.Orders.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	return items, total, nil
}

// GetOrderWithItems 查询单个订单详情
func (s *service) GetOrderWithItems(ctx context.Context, userID int64, orderID int64) (*OrderWithItems, error) {
	order, err := s.readDB.Orders.WithContext(ctx).ReadDB().Where(s.readDB.Orders.ID.Eq(orderID), s.readDB.Orders.UserID.Eq(userID)).First()
	if err != nil {
		return nil, err
	}
	if order == nil {
		return nil, nil
	}

	res := &OrderWithItems{
		Orders: order,
	}

	items, err := s.readDB.OrderItems.WithContext(ctx).ReadDB().Where(s.readDB.OrderItems.OrderID.Eq(order.ID)).Find()
	if err != nil {
		return nil, err
	}

	if len(items) > 0 {
		ids := make(map[int64]struct{})
		for _, it := range items {
			if strings.TrimSpace(it.Title) == "" || strings.TrimSpace(it.Title) == "系统发放奖励" || it.ProductImages == "" || it.ProductImages == "[]" {
				ids[it.ProductID] = struct{}{}
			}
		}
		if len(ids) > 0 {
			pidList := make([]int64, 0, len(ids))
			for id := range ids {
				pidList = append(pidList, id)
			}
			pros, err2 := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.In(pidList...)).Find()
			if err2 != nil {
				return nil, err2
			}
			pm := make(map[int64]*model.Products, len(pros))
			for _, p := range pros {
				pm[p.ID] = p
			}
			for _, it := range items {
				p := pm[it.ProductID]
				if p == nil {
					continue
				}
				if strings.TrimSpace(it.Title) == "" || strings.TrimSpace(it.Title) == "系统发放奖励" {
					it.Title = p.Name
				}
				if it.ProductImages == "" || it.ProductImages == "[]" {
					it.ProductImages = p.ImagesJSON
				}
			}
		}
		res.Items = items
	}

	// 补充优惠券和道具卡信息
	if order.CouponID > 0 || order.ItemCardID > 0 {
		if order.CouponID > 0 {
			if uc, _ := s.readDB.UserCoupons.WithContext(ctx).ReadDB().Where(s.readDB.UserCoupons.ID.Eq(order.CouponID)).First(); uc != nil {
				if sc, _ := s.readDB.SystemCoupons.WithContext(ctx).ReadDB().Where(s.readDB.SystemCoupons.ID.Eq(uc.CouponID)).First(); sc != nil {
					val := sc.DiscountValue
					if oc, _ := s.readDB.OrderCoupons.WithContext(ctx).ReadDB().Where(
						s.readDB.OrderCoupons.OrderID.Eq(order.ID),
						s.readDB.OrderCoupons.UserCouponID.Eq(order.CouponID),
					).First(); oc != nil {
						val = oc.AppliedAmount
					}
					res.CouponInfo = &CouponSimpleInfo{UserCouponID: uc.ID, Name: sc.Name, Type: sc.DiscountType, Value: val}
				}
			}
		}
		if order.ItemCardID > 0 {
			if uc, _ := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.ID.Eq(order.ItemCardID)).First(); uc != nil {
				if sc, _ := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.Eq(uc.CardID)).First(); sc != nil {
					res.ItemCardInfo = &ItemCardSimpleInfo{UserCardID: uc.ID, Name: sc.Name, EffectType: sc.EffectType}
				}
			}
		}
	}

	// 补充开奖和活动信息
	logs, _ := s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawLogs.OrderID.Eq(order.ID)).Find()
	if len(logs) > 0 {
		res.IsDraw = true
		res.IsWinner = logs[0].IsWinner == 1
		res.RewardLevel = logs[0].Level

		// 批量获取活动信息以减少查询次数
		issue, _ := s.readDB.ActivityIssues.WithContext(ctx).ReadDB().Where(s.readDB.ActivityIssues.ID.Eq(logs[0].IssueID)).First()
		if issue != nil {
			res.IssueNumber = issue.IssueNumber
			act, _ := s.readDB.Activities.WithContext(ctx).ReadDB().Where(s.readDB.Activities.ID.Eq(issue.ActivityID)).First()
			if act != nil {
				res.ActivityName = act.Name
				res.ActivityID = act.ID
				res.PlayType = act.PlayType
				res.CategoryID = act.ActivityCategoryID
				if act.ActivityCategoryID > 0 {
					cat, _ := s.readDB.ActivityCategories.WithContext(ctx).ReadDB().Where(s.readDB.ActivityCategories.ID.Eq(act.ActivityCategoryID)).First()
					if cat != nil {
						res.CategoryName = cat.Name
					}
				}
			}
		}

		// 批量查询凭据并一次性映射奖励ID
		drawLogIDs := make([]int64, len(logs))
		drawLogMap := make(map[int64]*model.ActivityDrawLogs, len(logs))
		for i, lg := range logs {
			drawLogIDs[i] = lg.ID
			drawLogMap[lg.ID] = lg
		}
		receipts, _ := s.readDB.ActivityDrawReceipts.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawReceipts.DrawLogID.In(drawLogIDs...)).Find()
		res.DrawReceipts = make([]*DrawReceiptInfo, 0, len(receipts))
		for _, r := range receipts {
			lg := drawLogMap[r.DrawLogID]
			res.DrawReceipts = append(res.DrawReceipts, &DrawReceiptInfo{
				DrawLogID: r.DrawLogID, RewardID: lg.RewardID, DrawIndex: int(lg.DrawIndex + 1),
				AlgoVersion: r.AlgoVersion, RoundID: r.RoundID, DrawID: r.DrawID, ClientID: r.ClientID,
				Timestamp: r.Timestamp, ServerSeedHash: r.ServerSeedHash, ClientSeed: r.ClientSeed,
				Nonce: r.Nonce, ItemsRoot: r.ItemsRoot, WeightsTotal: r.WeightsTotal,
				SelectedIndex: r.SelectedIndex, RandProof: r.RandProof, Signature: r.Signature, ItemsSnapshot: r.ItemsSnapshot,
			})
		}
	}

	if res.PlayType == "ichiban" {
		res.ItemCardInfo = nil
	}
	return res, nil
}

// ListOrdersWithItems 查询用户的订单列表，包含订单项详情
func (s *service) ListOrdersWithItems(ctx context.Context, userID int64, status int32, isConsumed *int32, page, pageSize int) (items []*OrderWithItems, total int64, err error) {
	// 查询用户的所有订单，包括商城直购(1)、抽奖票据(2)和系统发放(3)
	q := s.readDB.Orders.WithContext(ctx).ReadDB().Where(s.readDB.Orders.UserID.Eq(userID))
	if status > 0 {
		q = q.Where(s.readDB.Orders.Status.Eq(status))
	}
	if isConsumed != nil {
		q = q.Where(s.readDB.Orders.IsConsumed.Eq(*isConsumed))
	}
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}

	// 查询订单列表
	orders, err := q.Order(s.readDB.Orders.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}

	// 构建订单ID列表
	orderIDs := make([]int64, len(orders))
	for i, order := range orders {
		orderIDs[i] = order.ID
	}

	var allItems []*model.OrderItems
	if len(orderIDs) > 0 {
		allItems, err = s.readDB.OrderItems.WithContext(ctx).ReadDB().Where(s.readDB.OrderItems.OrderID.In(orderIDs...)).Find()
		if err != nil {
			return nil, 0, err
		}

		ids := make(map[int64]struct{})
		for _, it := range allItems {
			if strings.TrimSpace(it.Title) == "" || strings.TrimSpace(it.Title) == "系统发放奖励" || it.ProductImages == "" || it.ProductImages == "[]" {
				ids[it.ProductID] = struct{}{}
			}
		}
		if len(ids) > 0 {
			pidList := make([]int64, 0, len(ids))
			for id := range ids {
				pidList = append(pidList, id)
			}
			pros, err2 := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.In(pidList...)).Find()
			if err2 != nil {
				return nil, 0, err2
			}
			pm := make(map[int64]*model.Products, len(pros))
			for _, p := range pros {
				pm[p.ID] = p
			}
			for _, it := range allItems {
				p := pm[it.ProductID]
				if p == nil {
					continue
				}
				if strings.TrimSpace(it.Title) == "" || strings.TrimSpace(it.Title) == "系统发放奖励" {
					it.Title = p.Name
				}
				if it.ProductImages == "" || it.ProductImages == "[]" {
					it.ProductImages = p.ImagesJSON
				}
			}
		}
	}

	// 构建订单ID到订单项的映射
	itemsMap := make(map[int64][]*model.OrderItems)
	for _, item := range allItems {
		itemsMap[item.OrderID] = append(itemsMap[item.OrderID], item)
	}

	// 批量查询活动开奖信息
	drawLogsListMap := make(map[int64][]*model.ActivityDrawLogs) // orderID -> logs
	activityMap := make(map[int64]*model.Activities)
	issueMap := make(map[int64]*model.ActivityIssues)
	var allDrawLogIDs []int64

	if len(orderIDs) > 0 {
		logs, _ := s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawLogs.OrderID.In(orderIDs...)).Find()
		var issueIDs []int64
		for _, log := range logs {
			drawLogsListMap[log.OrderID] = append(drawLogsListMap[log.OrderID], log)
			issueIDs = append(issueIDs, log.IssueID)
			allDrawLogIDs = append(allDrawLogIDs, log.ID)
		}

		if len(issueIDs) > 0 {
			issues, _ := s.readDB.ActivityIssues.WithContext(ctx).ReadDB().Where(s.readDB.ActivityIssues.ID.In(issueIDs...)).Find()
			var activityIDs []int64
			for _, issue := range issues {
				issueMap[issue.ID] = issue
				activityIDs = append(activityIDs, issue.ActivityID)
			}

			if len(activityIDs) > 0 {
				activities, _ := s.readDB.Activities.WithContext(ctx).ReadDB().Where(s.readDB.Activities.ID.In(activityIDs...)).Find()
				for _, act := range activities {
					activityMap[act.ID] = act
				}
			}
		}

		// 为没有开奖记录的抽奖订单补充查询活动信息
		var extraActIDs []int64
		for _, order := range orders {
			if order.SourceType == 2 {
				if _, hasLogs := drawLogsListMap[order.ID]; !hasLogs {
					actID := parseActivityIDFromRemark(order.Remark)
					if actID > 0 {
						if _, exists := activityMap[actID]; !exists {
							extraActIDs = append(extraActIDs, actID)
						}
					}
				}
			}
		}
		if len(extraActIDs) > 0 {
			extraActs, _ := s.readDB.Activities.WithContext(ctx).ReadDB().Where(s.readDB.Activities.ID.In(extraActIDs...)).Find()
			for _, act := range extraActs {
				activityMap[act.ID] = act
			}
		}
	}

	// 批量查询活动分类信息
	categoryMap := make(map[int64]*model.ActivityCategories)
	var categoryIDs []int64
	for _, act := range activityMap {
		if act.ActivityCategoryID > 0 {
			categoryIDs = append(categoryIDs, act.ActivityCategoryID)
		}
	}
	if len(categoryIDs) > 0 {
		categories, _ := s.readDB.ActivityCategories.WithContext(ctx).ReadDB().Where(s.readDB.ActivityCategories.ID.In(categoryIDs...)).Find()
		for _, cat := range categories {
			categoryMap[cat.ID] = cat
		}
	}

	// 批量查询抽奖凭据
	receiptsMap := make(map[int64]*model.ActivityDrawReceipts) // drawLogID -> receipt
	if len(allDrawLogIDs) > 0 {
		receipts, _ := s.readDB.ActivityDrawReceipts.WithContext(ctx).ReadDB().Where(s.readDB.ActivityDrawReceipts.DrawLogID.In(allDrawLogIDs...)).Find()
		for _, r := range receipts {
			receiptsMap[r.DrawLogID] = r
		}
	}

	// 批量查询优惠券和道具卡信息
	userCouponIDs := make([]int64, 0)
	userItemCardIDs := make([]int64, 0)
	for _, order := range orders {
		if order.CouponID > 0 {
			userCouponIDs = append(userCouponIDs, order.CouponID)
		}
		if order.ItemCardID > 0 {
			userItemCardIDs = append(userItemCardIDs, order.ItemCardID)
		}
	}

	couponMap := make(map[int64]*CouponSimpleInfo)
	// orderID -> userCouponID -> appliedAmount
	appliedAmountMap := make(map[int64]map[int64]int64)

	if len(userCouponIDs) > 0 {
		// 查询优惠券基本信息
		userCoupons, _ := s.readDB.UserCoupons.WithContext(ctx).ReadDB().Where(s.readDB.UserCoupons.ID.In(userCouponIDs...)).Find()
		var sysCouponIDs []int64
		ucMap := make(map[int64]*model.UserCoupons)
		for _, uc := range userCoupons {
			sysCouponIDs = append(sysCouponIDs, uc.CouponID)
			ucMap[uc.ID] = uc
		}
		if len(sysCouponIDs) > 0 {
			sysCoupons, _ := s.readDB.SystemCoupons.WithContext(ctx).ReadDB().Where(s.readDB.SystemCoupons.ID.In(sysCouponIDs...)).Find()
			scMap := make(map[int64]*model.SystemCoupons)
			for _, sc := range sysCoupons {
				scMap[sc.ID] = sc
			}
			for id, uc := range ucMap {
				if sc, ok := scMap[uc.CouponID]; ok {
					couponMap[id] = &CouponSimpleInfo{
						UserCouponID: uc.ID,
						Name:         sc.Name,
						Type:         sc.DiscountType,
						Value:        sc.DiscountValue, // 默认使用面值，后面会尝试用实际抵扣金额覆盖
					}
				}
			}
		}

		// 查询订单实际使用的优惠券金额
		if len(orderIDs) > 0 {
			ocs, _ := s.readDB.OrderCoupons.WithContext(ctx).ReadDB().Where(
				s.readDB.OrderCoupons.OrderID.In(orderIDs...),
				s.readDB.OrderCoupons.UserCouponID.In(userCouponIDs...),
			).Find()
			for _, oc := range ocs {
				if _, ok := appliedAmountMap[oc.OrderID]; !ok {
					appliedAmountMap[oc.OrderID] = make(map[int64]int64)
				}
				appliedAmountMap[oc.OrderID][oc.UserCouponID] = oc.AppliedAmount
			}
		}
	}

	itemCardMap := make(map[int64]*ItemCardSimpleInfo)
	if len(userItemCardIDs) > 0 {
		userCards, _ := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.ID.In(userItemCardIDs...)).Find()
		var sysCardIDs []int64
		ucMap := make(map[int64]*model.UserItemCards)
		for _, uc := range userCards {
			sysCardIDs = append(sysCardIDs, uc.CardID)
			ucMap[uc.ID] = uc
		}
		if len(sysCardIDs) > 0 {
			sysCards, _ := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(sysCardIDs...)).Find()
			scMap := make(map[int64]*model.SystemItemCards)
			for _, sc := range sysCards {
				scMap[sc.ID] = sc
			}
			for id, uc := range ucMap {
				if sc, ok := scMap[uc.CardID]; ok {
					itemCardMap[id] = &ItemCardSimpleInfo{
						UserCardID: uc.ID,
						Name:       sc.Name,
						EffectType: sc.EffectType,
					}
				}
			}
		}
	}

	// 构建返回结果
	items = make([]*OrderWithItems, len(orders))
	for i, order := range orders {
		// 复制一份 CouponInfo，因为同一个优惠券可能被多个订单使用，但金额不同
		var cInfo *CouponSimpleInfo
		if baseInfo, ok := couponMap[order.CouponID]; ok {
			cInfo = &CouponSimpleInfo{
				UserCouponID: baseInfo.UserCouponID,
				Name:         baseInfo.Name,
				Type:         baseInfo.Type,
				Value:        baseInfo.Value,
			}
			// 尝试使用实际抵扣金额
			if amMap, ok := appliedAmountMap[order.ID]; ok {
				if amount, ok2 := amMap[order.CouponID]; ok2 {
					cInfo.Value = amount
				}
			}
		}

		items[i] = &OrderWithItems{
			Orders:       order,
			Items:        itemsMap[order.ID],
			CouponInfo:   cInfo,
			ItemCardInfo: itemCardMap[order.ItemCardID],
		}

		if logs, ok := drawLogsListMap[order.ID]; ok && len(logs) > 0 {
			items[i].IsDraw = true
			// 取第一条记录的基本信息
			log := logs[0]
			items[i].IsWinner = log.IsWinner == 1
			items[i].RewardLevel = log.Level
			if issue, ok := issueMap[log.IssueID]; ok {
				items[i].IssueNumber = issue.IssueNumber
				if act, ok := activityMap[issue.ActivityID]; ok {
					items[i].ActivityName = act.Name
					items[i].ActivityID = act.ID
					items[i].PlayType = act.PlayType
					items[i].CategoryID = act.ActivityCategoryID
					if cat, ok := categoryMap[act.ActivityCategoryID]; ok {
						items[i].CategoryName = cat.Name
					}
				}
			}

			// 填充抽奖凭据
			for idx, lg := range logs {
				if r, ok := receiptsMap[lg.ID]; ok {
					items[i].DrawReceipts = append(items[i].DrawReceipts, &DrawReceiptInfo{
						DrawLogID:      r.DrawLogID,
						RewardID:       lg.RewardID,
						DrawIndex:      idx + 1,
						AlgoVersion:    r.AlgoVersion,
						RoundID:        r.RoundID,
						DrawID:         r.DrawID,
						ClientID:       r.ClientID,
						Timestamp:      r.Timestamp,
						ServerSeedHash: r.ServerSeedHash,
						ServerSubSeed:  "",
						ClientSeed:     r.ClientSeed,
						Nonce:          r.Nonce,
						ItemsRoot:      r.ItemsRoot,
						WeightsTotal:   r.WeightsTotal,
						SelectedIndex:  r.SelectedIndex,
						RandProof:      r.RandProof,
						Signature:      r.Signature,
						ItemsSnapshot:  r.ItemsSnapshot,
					})
				}
			}
		} else if order.SourceType == 2 {
			// 抽奖订单但没有开奖记录（如对对碰支付后还没玩），从备注解析活动信息
			actID := parseActivityIDFromRemark(order.Remark)
			if actID > 0 {
				if act, ok := activityMap[actID]; ok {
					items[i].ActivityName = act.Name
					items[i].ActivityID = act.ID
					items[i].PlayType = act.PlayType
					items[i].CategoryID = act.ActivityCategoryID
					if cat, ok := categoryMap[act.ActivityCategoryID]; ok {
						items[i].CategoryName = cat.Name
					}
				}
			}
		}

		// Special handling for Ichiban Kuji: Do not show Item Card
		if items[i].PlayType == "ichiban" {
			items[i].ItemCardInfo = nil
		}
	}

	return items, total, nil
}

// parseActivityIDFromRemark 从订单备注解析活动ID
func parseActivityIDFromRemark(remark string) int64 {
	if remark == "" {
		return 0
	}
	parts := strings.Split(remark, "|")
	for _, p := range parts {
		if strings.HasPrefix(p, "lottery:activity:") {
			idStr := p[len("lottery:activity:"):]
			var n int64
			for i := 0; i < len(idStr); i++ {
				c := idStr[i]
				if c < '0' || c > '9' {
					break
				}
				n = n*10 + int64(c-'0')
			}
			return n
		}
	}
	return 0
}
