package activity

import (
	"bindbox-game/internal/pkg/core"
	"bindbox-game/internal/pkg/logger"
	"bindbox-game/internal/repository/mysql"
	"bindbox-game/internal/repository/mysql/dao"
	"bindbox-game/internal/repository/mysql/model"
	titlesvc "bindbox-game/internal/service/title"
	usersvc "bindbox-game/internal/service/user"
	"context"
	"encoding/json"
	"fmt"
	"time"
)

// ActivityOrderService 活动订单创建服务
// 统一处理一番赏和对对碰的订单创建逻辑
type ActivityOrderService interface {
	// CreateActivityOrder 创建活动订单
	// 统一处理优惠券、称号折扣、道具卡记录等
	CreateActivityOrder(ctx core.Context, req CreateActivityOrderRequest) (*CreateActivityOrderResult, error)
}

// CreateActivityOrderRequest 订单创建请求
type CreateActivityOrderRequest struct {
	UserID      int64  // 用户ID
	ActivityID  int64  // 活动ID
	IssueID     int64  // 期ID
	Count       int64  // 数量
	UnitPrice   int64  // 单价（分）
	SourceType  int32  // 订单来源类型: 2=抽奖, 3=对对碰
	CouponID    *int64 // 优惠券ID（可选）
	ItemCardID  *int64 // 道具卡ID（可选）
	ExtraRemark string // 额外备注信息
}

// CreateActivityOrderResult 订单创建结果
type CreateActivityOrderResult struct {
	Order            *model.Orders // 创建的订单
	AppliedCouponVal int64         // 应用的优惠券抵扣金额
}

type activityOrderService struct {
	logger  logger.CustomLogger
	readDB  *dao.Query
	writeDB *dao.Query
	repo    mysql.Repo
	title   titlesvc.Service
	user    usersvc.Service
}

// NewActivityOrderService 创建活动订单服务
func NewActivityOrderService(l logger.CustomLogger, db mysql.Repo) ActivityOrderService {
	return &activityOrderService{
		logger:  l,
		readDB:  dao.Use(db.GetDbR()),
		writeDB: dao.Use(db.GetDbW()),
		repo:    db,
		title:   titlesvc.New(l, db),
		user:    usersvc.New(l, db),
	}
}

// CreateActivityOrder 创建活动订单
func (s *activityOrderService) CreateActivityOrder(ctx core.Context, req CreateActivityOrderRequest) (*CreateActivityOrderResult, error) {
	userID := req.UserID
	count := req.Count
	if count <= 0 {
		count = 1
	}
	total := req.UnitPrice * count

	// 1. 创建订单基础信息
	orderNo := fmt.Sprintf("O%s%03d", time.Now().Format("20060102150405"), time.Now().UnixNano()%1000)
	order := &model.Orders{
		UserID:       userID,
		OrderNo:      orderNo,
		SourceType:   req.SourceType,
		TotalAmount:  total,
		ActualAmount: total,
		Status:       1, // Pending
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
	}

	// 设置备注
	if req.ExtraRemark != "" {
		order.Remark = req.ExtraRemark
	} else {
		order.Remark = fmt.Sprintf("activity:%d|issue:%d|count:%d", req.ActivityID, req.IssueID, count)
	}

	// 记录优惠券和道具卡信息（显式字段 + 备注追加）
	if req.CouponID != nil && *req.CouponID > 0 {
		order.CouponID = *req.CouponID
		order.Remark += fmt.Sprintf("|coupon:%d", *req.CouponID)
	}
	if req.ItemCardID != nil && *req.ItemCardID > 0 {
		order.ItemCardID = *req.ItemCardID
		order.Remark += fmt.Sprintf("|itemcard:%d", *req.ItemCardID)
	}

	// 2. 应用称号折扣 (Title Discount)
	titleEffects, _ := s.title.ResolveActiveEffects(ctx.RequestContext(), userID, titlesvc.EffectScope{
		ActivityID: &req.ActivityID,
		IssueID:    &req.IssueID,
	})
	for _, ef := range titleEffects {
		if ef.EffectType == 2 { // Discount effect
			var p struct {
				DiscountType     string `json:"discount_type"`
				ValueX1000       int64  `json:"value_x1000"`
				MaxDiscountX1000 int64  `json:"max_discount_x1000"`
			}
			if jsonErr := json.Unmarshal([]byte(ef.ParamsJSON), &p); jsonErr == nil {
				var discount int64
				if p.DiscountType == "percentage" {
					discount = order.ActualAmount * p.ValueX1000 / 1000
				} else if p.DiscountType == "fixed" {
					discount = p.ValueX1000
				}
				if p.MaxDiscountX1000 > 0 && discount > p.MaxDiscountX1000 {
					discount = p.MaxDiscountX1000
				}
				if discount > order.ActualAmount {
					discount = order.ActualAmount
				}
				if discount > 0 {
					order.ActualAmount -= discount
					order.Remark += fmt.Sprintf("|title_discount:%d:%d", ef.ID, discount)
				}
			}
		}
	}

	// 3. 应用优惠券 (using applyCouponWithCap logic)
	var appliedCouponVal int64
	if req.CouponID != nil && *req.CouponID > 0 {
		fmt.Printf("[订单服务] 尝试优惠券 用户券ID=%d 应用前实付(分)=%d\n", *req.CouponID, order.ActualAmount)
		appliedCouponVal = s.applyCouponWithCap(ctx.RequestContext(), userID, order, req.ActivityID, *req.CouponID)
		fmt.Printf("[订单服务] 优惠后 实付(分)=%d 累计优惠(分)=%d\n", order.ActualAmount, order.DiscountAmount)
	}

	// 4. 记录道具卡到备注 (Removed duplicate append here as it was already done in Step 1)
	// Log for debugging
	if req.ItemCardID != nil && *req.ItemCardID > 0 {
		fmt.Printf("[订单服务] 尝试道具卡 用户卡ID=%d 订单号=%s\n", *req.ItemCardID, order.OrderNo)
	}

	// 5. 保存订单
	if err := s.writeDB.Orders.WithContext(ctx.RequestContext()).Omit(s.writeDB.Orders.PaidAt, s.writeDB.Orders.CancelledAt).Create(order); err != nil {
		return nil, err
	}

	// 6. 记录优惠券使用明细
	if appliedCouponVal > 0 && req.CouponID != nil && *req.CouponID > 0 {
		_ = s.user.RecordOrderCouponUsage(ctx.RequestContext(), order.ID, *req.CouponID, appliedCouponVal)
	}

	// 7. 处理0元订单自动支付
	if order.ActualAmount == 0 {
		now := time.Now()
		_, _ = s.writeDB.Orders.WithContext(ctx.RequestContext()).Where(s.writeDB.Orders.OrderNo.Eq(orderNo)).Updates(map[string]any{
			s.writeDB.Orders.Status.ColumnName().String(): 2,
			s.writeDB.Orders.PaidAt.ColumnName().String(): now,
		})
		order.Status = 2

		// 核销优惠券
		if req.CouponID != nil && *req.CouponID > 0 {
			s.consumeCouponOnZeroPay(ctx.RequestContext(), userID, order.ID, *req.CouponID, appliedCouponVal, now)
		}
	}

	fmt.Printf("[订单服务] 订单创建完成 订单号=%s 总额(分)=%d 优惠(分)=%d 实付(分)=%d 状态=%d\n",
		order.OrderNo, order.TotalAmount, order.DiscountAmount, order.ActualAmount, order.Status)

	return &CreateActivityOrderResult{
		Order:            order,
		AppliedCouponVal: appliedCouponVal,
	}, nil
}

// applyCouponWithCap 优惠券抵扣（含50%封顶与金额券部分使用）
func (s *activityOrderService) applyCouponWithCap(ctx context.Context, userID int64, order *model.Orders, activityID int64, userCouponID int64) int64 {
	uc, _ := s.readDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.ID.Eq(userCouponID), s.readDB.UserCoupons.UserID.Eq(userID), s.readDB.UserCoupons.Status.Eq(1)).First()
	if uc == nil {
		return 0
	}
	fmt.Printf("[优惠券] 用户券ID=%d 开始=%s 结束=%s\n", userCouponID, uc.ValidStart.Format(time.RFC3339), func() string {
		if uc.ValidEnd.IsZero() {
			return "无截止"
		}
		return uc.ValidEnd.Format(time.RFC3339)
	}())
	sc, _ := s.readDB.SystemCoupons.WithContext(ctx).Where(s.readDB.SystemCoupons.ID.Eq(uc.CouponID), s.readDB.SystemCoupons.Status.Eq(1)).First()
	now := time.Now()
	if sc == nil {
		fmt.Printf("[优惠券] 模板不存在 用户券ID=%d\n", userCouponID)
		return 0
	}
	if uc.ValidStart.After(now) {
		fmt.Printf("[优惠券] 未到开始时间 用户券ID=%d\n", userCouponID)
		return 0
	}
	if !uc.ValidEnd.IsZero() && uc.ValidEnd.Before(now) {
		fmt.Printf("[优惠券] 已过期 用户券ID=%d\n", userCouponID)
		return 0
	}
	scopeOK := (sc.ScopeType == 1) || (sc.ScopeType == 2 && sc.ActivityID == activityID)
	if !scopeOK {
		fmt.Printf("[优惠券] 范围不匹配 用户券ID=%d scope_type=%d\n", userCouponID, sc.ScopeType)
		return 0
	}
	if order.TotalAmount < sc.MinSpend {
		fmt.Printf("[优惠券] 未达使用门槛 用户券ID=%d min_spend(分)=%d 订单总额(分)=%d\n", userCouponID, sc.MinSpend, order.TotalAmount)
		return 0
	}

	// 50% 封顶
	cap := order.TotalAmount / 2
	remainingCap := cap - order.DiscountAmount
	if remainingCap <= 0 {
		fmt.Printf("[优惠券] 已达封顶\n")
		return 0
	}

	applied := int64(0)
	switch sc.DiscountType {
	case 1: // 金额券
		var bal int64
		_ = s.repo.GetDbR().Raw("SELECT COALESCE(balance_amount,0) FROM user_coupons WHERE id=?", userCouponID).Scan(&bal).Error
		if bal <= 0 {
			bal = sc.DiscountValue
		}
		if bal > 0 {
			if bal > remainingCap {
				applied = remainingCap
			} else {
				applied = bal
			}
		}
	case 2: // 满减券
		applied = sc.DiscountValue
		if applied > remainingCap {
			applied = remainingCap
		}
	case 3: // 折扣券
		rate := sc.DiscountValue
		if rate < 0 {
			rate = 0
		}
		if rate > 1000 {
			rate = 1000
		}
		newAmt := order.ActualAmount * rate / 1000
		d := order.ActualAmount - newAmt
		if d > remainingCap {
			applied = remainingCap
		} else {
			applied = d
		}
	}

	if applied > order.ActualAmount {
		applied = order.ActualAmount
	}
	if applied <= 0 {
		return 0
	}

	order.ActualAmount -= applied
	order.DiscountAmount += applied
	order.Remark += fmt.Sprintf("|c:%d:%d", userCouponID, applied)
	fmt.Printf("[优惠券] 本次抵扣(分)=%d\n", applied)

	return applied
}

// consumeCouponOnZeroPay 0元支付时核销优惠券
func (s *activityOrderService) consumeCouponOnZeroPay(ctx context.Context, userID int64, orderID int64, userCouponID int64, applied int64, now time.Time) {
	uc, _ := s.readDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.ID.Eq(userCouponID), s.readDB.UserCoupons.UserID.Eq(userID)).First()
	if uc == nil {
		return
	}
	sc, _ := s.readDB.SystemCoupons.WithContext(ctx).Where(s.readDB.SystemCoupons.ID.Eq(uc.CouponID)).First()
	if sc == nil {
		return
	}

	if sc.DiscountType == 1 { // 金额券 - 部分扣减
		var bal int64
		_ = s.repo.GetDbR().Raw("SELECT COALESCE(balance_amount,0) FROM user_coupons WHERE id=?", userCouponID).Scan(&bal).Error
		nb := bal - applied
		if nb < 0 {
			nb = 0
		}
		if nb == 0 {
			_, _ = s.writeDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.ID.Eq(userCouponID)).Updates(map[string]any{
				"balance_amount": nb,
				s.readDB.UserCoupons.Status.ColumnName().String():      2,
				s.readDB.UserCoupons.UsedOrderID.ColumnName().String(): orderID,
				s.readDB.UserCoupons.UsedAt.ColumnName().String():      now,
			})
		} else {
			_, _ = s.writeDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.ID.Eq(userCouponID)).Updates(map[string]any{
				"balance_amount": nb,
				s.readDB.UserCoupons.UsedOrderID.ColumnName().String(): orderID,
				s.readDB.UserCoupons.UsedAt.ColumnName().String():      now,
			})
		}
	} else { // 满减/折扣券 - 直接核销
		_, _ = s.writeDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.ID.Eq(userCouponID)).Updates(map[string]any{
			s.readDB.UserCoupons.Status.ColumnName().String():      2,
			s.readDB.UserCoupons.UsedOrderID.ColumnName().String(): orderID,
			s.readDB.UserCoupons.UsedAt.ColumnName().String():      now,
		})
	}
}
