package jd_cookie

import (
	"context"
	"kami/internal/consts"
	"kami/internal/model"
	"kami/internal/model/entity"
	"kami/utility/cache"
	"kami/utility/utils"
	"slices"
	"strings"
	"time"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
)

// CreateOrder 创建订单
func (s *sJdCookie) CreateOrder(ctx context.Context, req *model.CreateOrderReq) (result *model.CreateOrderResult, err error) {
	if req.UserOrderId == "" {
		return nil, gerror.New("用户订单号不能为空")
	}
	if req.Amount <= 0 {
		return nil, gerror.New("订单金额必须大于0")
	}

	// 获取用户订单分布式锁，防止并发创建重复订单
	lockKey := consts.OrderLockKeyPrefix + req.UserOrderId
	lockValue, err := cache.NewCache().Lock(ctx, lockKey, time.Minute*3, time.Second*60)
	if err != nil {
		return nil, gerror.Wrap(err, "系统繁忙，请稍后重试")
	}

	// 确保锁会被释放
	defer func() {
		if unlockErr := cache.NewCache().Unlock(ctx, lockKey, lockValue); unlockErr != nil {
			glog.Warning(ctx, "释放分布式锁失败", g.Map{
				"lockKey": lockKey,
				"error":   unlockErr,
			})
		}
	}()

	// 在锁保护下再次检查用户订单是否已存在（双重检查）
	existingOrder, err := s.getOrderByUserOrderId(ctx, req.UserOrderId)
	if err != nil {
		return nil, gerror.Wrap(err, "检查用户订单是否存在失败")
	}

	if existingOrder != nil {
		// 订单已存在，检查订单状态
		if !slices.Contains([]consts.OrderStatus{
			consts.OrderStatusJDOrderFailed, consts.OrderStatusCreated, consts.OrderStatusPending,
		}, consts.OrderStatus(existingOrder.Status)) {
			return nil, gerror.New("订单已完成")
		}
		// 如果订单状态为失败(Ck失败)，重新尝试创建京东订单
		if consts.OrderStatus(existingOrder.Status) == consts.OrderStatusJDOrderFailed {
			glog.Info(ctx, "检测到失败订单，尝试重新创建京东订单", g.Map{
				"orderId":     existingOrder.OrderId,
				"userOrderId": req.UserOrderId,
				"status":      consts.OrderStatus(existingOrder.Status),
			})

			// 尝试重新创建京东订单
			retryResult, retryErr := s.retryCreateJdOrderForFailedOrder(ctx, existingOrder, req)
			if retryErr != nil {
				// 重试失败，返回错误
				return nil, retryErr
			}

			// 重试成功，返回新的订单信息
			return retryResult, nil
		}

		// 订单状态正常，尝试获取支付链接
		paymentResult, err := s.GetPaymentUrl(ctx, req.UserOrderId, existingOrder.OrderId)
		if err != nil {
			return nil, err
		}
		// 转换为CreateOrderResult
		return &model.CreateOrderResult{
			WxPayUrl:  paymentResult.WxPayUrl,
			JdOrderId: paymentResult.JdOrderId,
			OrderId:   paymentResult.OrderId,
		}, nil
	}

	// 生成内部订单ID
	internalOrderId := "JD_" + utils.GenerateRandomUUID()

	// 先创建本地订单记录（状态为待支付，京东订单ID暂时为空）
	err = s.createOrderRecord(ctx, internalOrderId, req.UserOrderId, req.Amount, req.Category, "", "")
	if err != nil {
		return nil, gerror.Wrap(err, "创建订单记录失败")
	}

	// 记录订单创建历史
	_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
		OrderId:    internalOrderId,
		ChangeType: consts.OrderChangeTypeCreate,
		JdOrderId:  "",
		Remark:     "",
	})

	glog.Info(ctx, "本地订单创建成功，开始创建京东订单", g.Map{
		"orderId":     internalOrderId,
		"userOrderId": req.UserOrderId,
		"amount":      req.Amount,
	})

	// 优先尝试复用现有的京东订单
	reusableJdOrder, err := s.findReusableJdOrder(ctx, req.Amount, req.Category)
	if err != nil {
		glog.Warning(ctx, "查找可复用京东订单失败", err)
	}

	var cookieId, jdOrderId, wxPayUrl string
	var jdOrderErr error
	var isReused = false

	if reusableJdOrder != nil {
		// 尝试使用可复用的京东订单
		jdOrderId = reusableJdOrder.JdOrderId
		cookieId = reusableJdOrder.CookieId
		wxPayUrl = reusableJdOrder.WxPayUrl

		// 检查支付链接是否过期
		if reusableJdOrder.WxPayExpireAt != nil && gtime.Now().After(reusableJdOrder.WxPayExpireAt) {
			// 支付链接已过期，尝试刷新
			newWxPayUrl, isCkFailed, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
				JdOrderId: jdOrderId,
				PayId:     reusableJdOrder.PayId,
				CookieId:  cookieId,
			})
			if isCkFailed {
				s.handleCookieFailure(ctx, req.UserOrderId, cookieId, jdOrderId, isCkFailed, refreshErr.Error())
			}
			if refreshErr != nil {
				glog.Warning(ctx, "刷新支付链接失败，将创建新订单", g.Map{
					"jdOrderId": jdOrderId,
					"error":     refreshErr,
				})
				// 刷新失败，标记为不可复用
				_ = s.UpdateJdOrderStatus(ctx, jdOrderId, consts.JdOrderStatusExpired, "", refreshErr.Error())

				// 记录Cookie刷新失败历史
				_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
					CookieId:     cookieId,
					ChangeType:   consts.CookieChangeTypeRefreshFail,
					StatusBefore: consts.JdCookieStatusUnknown,
					StatusAfter:  consts.JdCookieStatusExpired,
					UserOrderId:  req.UserOrderId,
					OrderId:      internalOrderId,
					FailureCount: 0,
					Remark:       "刷新支付链接失败",
				})

				// 清空，准备创建新订单
				jdOrderId = ""
				cookieId = ""
				wxPayUrl = ""
			} else {
				wxPayUrl = newWxPayUrl
				// 更新京东订单的支付链接和过期时间
				_ = s.updateJdOrderPaymentUrl(ctx, jdOrderId, wxPayUrl)
				isReused = true
			}
		} else {
			isReused = true
		}

		if isReused {
			glog.Info(ctx, "复用现有京东订单", g.Map{
				"orderId":   internalOrderId,
				"jdOrderId": jdOrderId,
				"cookieId":  cookieId,
			})
		}
	}

	// 如果没有成功复用，创建新的京东订单
	if jdOrderId == "" {
		retryRes, retryErr := s.createNewJdOrderWithRetry(ctx, &model.CreateNewJdOrderWithRetryReq{
			OrderId:     internalOrderId,
			Amount:      req.Amount,
			Category:    req.Category,
			UserOrderId: req.UserOrderId,
		})
		if retryErr != nil {
			// 京东订单创建失败，更新本地订单状态和失败原因
			jdOrderErr = retryErr
			// 京东订单创建失败，更新本地订单失败原因
			if strings.Contains(retryErr.Error(), "库存问题") {
				_ = s.updateOrderFailure(ctx, internalOrderId, consts.OrderStatusStockFailed)
				// 记录订单重试失败的变更历史
				_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
					OrderId:    internalOrderId,
					ChangeType: consts.OrderChangeTypeStockFailed,
					JdOrderId:  "",
					Remark:     retryErr.Error(),
				})
			} else {
				_ = s.updateOrderFailure(ctx, internalOrderId, consts.OrderStatusJDOrderFailed)
				// 记录订单重试失败的变更历史
				_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
					OrderId:    internalOrderId,
					ChangeType: consts.OrderChangeTypeJDOrderFailed,
					JdOrderId:  "",
					Remark:     retryErr.Error(),
				})
			}
			// 记录订单创建失败的变更历史
			_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
				OrderId:    internalOrderId,
				ChangeType: consts.OrderChangeTypeJDOrderFailed,
				JdOrderId:  "",
				Remark:     jdOrderErr.Error(),
			})

			glog.Error(ctx, "京东订单创建失败", g.Map{
				"orderId":       internalOrderId,
				"userOrderId":   req.UserOrderId,
				"failureReason": retryErr.Error(),
			})
			return nil, retryErr
		}
		jdOrderId = retryRes.JdOrderId
		cookieId = retryRes.CookieId
		wxPayUrl = retryRes.WxPayUrl
	}

	// 京东订单创建成功，更新本地订单的京东订单ID和支付链接
	err = s.updateOrderJdOrderId(ctx, internalOrderId, jdOrderId)
	if err != nil {
		glog.Error(ctx, "更新订单京东订单ID失败", g.Map{
			"orderId":   internalOrderId,
			"jdOrderId": jdOrderId,
			"error":     err,
		})
		return nil, gerror.Wrap(err, "更新订单信息失败")
	}

	// 京东订单创建成功，更新本地订单状态为待支付，并关联京东订单
	err = s.updateOrderSuccess(ctx, internalOrderId, jdOrderId)
	if err != nil {
		glog.Error(ctx, "更新订单状态失败", g.Map{
			"orderId":   internalOrderId,
			"jdOrderId": jdOrderId,
			"error":     err,
		})
		return nil, gerror.Wrap(err, "更新订单信息失败")
	}

	// 更新京东订单的当前关联订单ID
	_ = s.updateJdOrderId(ctx, jdOrderId, internalOrderId)

	// 记录Cookie使用历史
	_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
		CookieId:     cookieId,
		ChangeType:   consts.CookieChangeTypeUse,
		StatusBefore: consts.JdCookieStatusUnknown,
		StatusAfter:  consts.JdCookieStatusNormal,
		OrderId:      internalOrderId,
		UserOrderId:  req.UserOrderId,
		FailureCount: 0,
		Remark:       "Cookie用于创建订单",
	})

	// 记录订单绑定京东订单的变更历史
	_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
		OrderId:    internalOrderId,
		ChangeType: consts.OrderChangeTypeBind,
		JdOrderId:  jdOrderId,
		Remark:     "",
	})

	return &model.CreateOrderResult{
		WxPayUrl:  wxPayUrl,
		JdOrderId: jdOrderId,
		OrderId:   internalOrderId,
	}, nil
}

// createNewJdOrderWithRetry 创建新的京东订单（带重试机制）
func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.CreateNewJdOrderWithRetryReq) (res *model.CreateNewJdOrderWithRetryRes, err error) {
	var lastErr error
	var triedCookies []string // 记录已尝试的Cookie

	// 不断尝试，直到没有Cookie为止
	for {
		// 获取可用的Cookie
		availableCookieId, cookieErr := s.GetAvailableCookie(ctx)
		if cookieErr != nil {
			glog.Warning(ctx, "获取可用Cookie失败", g.Map{
				"orderId":      req.OrderId,
				"triedCookies": len(triedCookies),
				"error":        cookieErr,
			})
			lastErr = cookieErr
			break // 没有可用Cookie，停止重试
		}

		// 检查是否已经尝试过这个Cookie
		if s.hasCookieBeenTried(triedCookies, availableCookieId) {
			glog.Debug(ctx, "Cookie已被尝试过，跳过", g.Map{
				"cookieId": availableCookieId,
			})
			continue
		}

		// 记录已尝试的Cookie
		triedCookies = append(triedCookies, availableCookieId)

		jdOrderId := utils.GenerateRandomUUID()
		// 调用京东下单接口
		createOrderRes, lastErr := s.callJdCreateOrder(ctx, &model.CallJdCreateOrderReq{
			JdOrderId: jdOrderId,
			CookieId:  availableCookieId,
			Amount:    req.Amount,
			Category:  req.Category,
		})
		if lastErr != nil {
			glog.Warning(ctx, "京东下单失败，尝试切换Cookie重试", g.Map{
				"orderId":        req.OrderId,
				"cookieId":       availableCookieId,
				"triedCookies":   len(triedCookies),
				"error":          lastErr,
				"createOrderRes": createOrderRes,
			})

			isCkFailed := false
			remark := ""
			if createOrderRes != nil {
				remark = createOrderRes.Remark
				isCkFailed = createOrderRes.IsCkError
			}
			_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
				OrderId:    req.OrderId,
				ChangeType: consts.OrderChangeTypeJDOrderFailed,
				JdOrderId:  "",
				Remark:     remark,
			})

			if createOrderRes != nil && createOrderRes.IsStockError {
				// 记录失败历史
				_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
					CookieId:     availableCookieId,
					ChangeType:   consts.CookieChangeTypeFail,
					StatusBefore: consts.JdCookieStatusNormal,
					StatusAfter:  consts.JdCookieStatusNormal,
					OrderId:      req.OrderId,
					UserOrderId:  req.UserOrderId,
					FailureCount: 0,
					Remark:       remark,
				})
				err = gerror.New("库存错误" + lastErr.Error())
				break
			}

			// Cookie失败，更新状态
			s.handleCookieFailure(ctx, req.UserOrderId, availableCookieId, "", isCkFailed, remark)

			// 继续下一次重试
			continue
		}

		// 下单成功，创建京东订单记录
		err = s.createJdOrderRecord(ctx, &model.CreateJdOrderRecordReq{
			JdOrderId:     jdOrderId,                    // 内部订单号
			RealJdOrderId: createOrderRes.RealJdOrderId, // 京东客户端返回的真实订单ID
			PayId:         createOrderRes.PayId,
			CookieId:      availableCookieId,
			Category:      req.Category,
			Amount:        req.Amount,
			WxPayUrl:      createOrderRes.WxPayUrl,
		})
		if err != nil {
			glog.Error(ctx, "创建京东订单记录失败", g.Map{
				"jdOrderId": jdOrderId,
				"error":     err,
			})
			return nil, gerror.Wrap(err, "创建京东订单记录失败")
		}

		// 记录京东订单创建历史
		_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, req.OrderId, createOrderRes.WxPayUrl, "")

		glog.Info(ctx, "创建京东订单成功", g.Map{
			"orderId":      req.OrderId,
			"jdOrderId":    jdOrderId,
			"cookieId":     availableCookieId,
			"triedCookies": len(triedCookies),
		})

		// 返回成功结果
		return &model.CreateNewJdOrderWithRetryRes{
			JdOrderId: jdOrderId,
			CookieId:  availableCookieId,
			WxPayUrl:  createOrderRes.WxPayUrl,
		}, nil
	}

	// 所有重试都失败了
	if lastErr == nil {
		lastErr = gerror.New(consts.ErrCodeCookieNotAvailable)
	}

	glog.Error(ctx, "创建京东订单失败，所有Cookie均不可用", g.Map{
		"orderId":      req.OrderId,
		"triedCookies": triedCookies,
		"error":        lastErr,
	})

	return nil, gerror.Wrapf(lastErr, "创建京东订单失败，已尝试%d个Cookie", len(triedCookies))
}

// hasCookieBeenTried 检查Cookie是否已经尝试过
func (s *sJdCookie) hasCookieBeenTried(triedCookies []string, cookieId string) bool {
	for _, tried := range triedCookies {
		if tried == cookieId {
			return true
		}
	}
	return false
}

// retryCreateJdOrderForFailedOrder 为失败的订单重新创建京东订单
func (s *sJdCookie) retryCreateJdOrderForFailedOrder(ctx context.Context, existingOrder *entity.V1JdCookieOrder, req *model.CreateOrderReq) (result *model.CreateOrderResult, err error) {
	glog.Info(ctx, "开始为失败订单重新创建京东订单", g.Map{
		"orderId":     existingOrder.OrderId,
		"userOrderId": existingOrder.UserOrderId,
		"amount":      existingOrder.Amount,
	})

	// 优先尝试复用现有的京东订单
	reusableJdOrder, err := s.findReusableJdOrder(ctx, gconv.Float64(existingOrder.Amount), consts.RedeemOrderCardCategory(existingOrder.Category))
	if err != nil {
		glog.Warning(ctx, "查找可复用京东订单失败", err)
	}

	var cookieId, jdOrderId, wxPayUrl string
	var isReused = false

	if reusableJdOrder != nil {
		// 尝试使用可复用的京东订单
		jdOrderId = reusableJdOrder.JdOrderId
		cookieId = reusableJdOrder.CookieId
		wxPayUrl = reusableJdOrder.WxPayUrl

		// 检查支付链接是否过期
		if reusableJdOrder.WxPayExpireAt != nil && gtime.Now().After(reusableJdOrder.WxPayExpireAt) {
			// 支付链接已过期，尝试刷新
			newWxPayUrl, isCkFailed, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
				JdOrderId: jdOrderId,
				PayId:     reusableJdOrder.PayId,
				CookieId:  cookieId,
			})
			if isCkFailed {
				s.handleCookieFailure(ctx, req.UserOrderId, cookieId, jdOrderId, isCkFailed, refreshErr.Error())
			}
			if refreshErr != nil {
				glog.Warning(ctx, "刷新支付链接失败，将创建新订单", g.Map{
					"jdOrderId": jdOrderId,
					"error":     refreshErr,
				})
				// 刷新失败，标记为不可复用
				_ = s.UpdateJdOrderStatus(ctx, jdOrderId, consts.JdOrderStatusExpired, "", refreshErr.Error())

				// 清空，准备创建新订单
				jdOrderId = ""
				cookieId = ""
				wxPayUrl = ""
			} else {
				wxPayUrl = newWxPayUrl
				// 更新京东订单的支付链接和过期时间
				_ = s.updateJdOrderPaymentUrl(ctx, jdOrderId, wxPayUrl)
				isReused = true
			}
		} else {
			isReused = true
		}

		if isReused {
			glog.Info(ctx, "复用现有京东订单", g.Map{
				"orderId":   existingOrder.OrderId,
				"jdOrderId": jdOrderId,
				"cookieId":  cookieId,
			})
		}
	}

	// 如果没有成功复用，创建新的京东订单
	if jdOrderId == "" {
		retryRes, retryErr := s.createNewJdOrderWithRetry(ctx, &model.CreateNewJdOrderWithRetryReq{
			OrderId:     existingOrder.OrderId,
			Amount:      gconv.Float64(existingOrder.Amount),
			Category:    consts.RedeemOrderCardCategory(existingOrder.Category),
			UserOrderId: existingOrder.UserOrderId,
		})
		if retryErr != nil {
			// 京东订单创建失败，更新本地订单失败原因
			if strings.Contains(retryErr.Error(), "库存问题") {
				_ = s.updateOrderFailure(ctx, existingOrder.OrderId, consts.OrderStatusStockFailed)
				// 记录订单重试失败的变更历史
				_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
					OrderId:    existingOrder.OrderId,
					ChangeType: consts.OrderChangeTypeStockFailed,
					JdOrderId:  "",
					Remark:     retryErr.Error(),
				})
			} else {
				_ = s.updateOrderFailure(ctx, existingOrder.OrderId, consts.OrderStatusJDOrderFailed)
				// 记录订单重试失败的变更历史
				_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
					OrderId:    existingOrder.OrderId,
					ChangeType: consts.OrderChangeTypeJDOrderFailed,
					JdOrderId:  "",
					Remark:     retryErr.Error(),
				})
			}

			glog.Error(ctx, "重试创建京东订单失败", g.Map{
				"orderId":       existingOrder.OrderId,
				"userOrderId":   existingOrder.UserOrderId,
				"failureReason": retryErr.Error(),
			})
			return nil, retryErr
		}
		jdOrderId = retryRes.JdOrderId
		cookieId = retryRes.CookieId
		wxPayUrl = retryRes.WxPayUrl
	}

	// 京东订单创建成功，更新本地订单状态为待支付，并关联京东订单
	err = s.updateOrderSuccess(ctx, existingOrder.OrderId, jdOrderId)
	if err != nil {
		glog.Error(ctx, "更新订单状态失败", g.Map{
			"orderId":   existingOrder.OrderId,
			"jdOrderId": jdOrderId,
			"error":     err,
		})
		return nil, gerror.Wrap(err, "更新订单信息失败")
	}

	// 更新京东订单的当前关联订单ID
	_ = s.updateJdOrderId(ctx, jdOrderId, existingOrder.OrderId)

	// 记录Cookie使用历史
	_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
		CookieId:     cookieId,
		ChangeType:   consts.CookieChangeTypeUse,
		StatusBefore: consts.JdCookieStatusUnknown,
		StatusAfter:  consts.JdCookieStatusNormal,
		OrderId:      existingOrder.OrderId,
		UserOrderId:  existingOrder.UserOrderId,
		FailureCount: 0,
		Remark:       "失败订单重试成功",
	})

	// 记录订单重新绑定历史
	_ = s.RecordOrderHistory(ctx, &model.RecordOrderHistoryReq{
		OrderId:    existingOrder.OrderId,
		ChangeType: consts.OrderChangeTypeBind,
		JdOrderId:  jdOrderId,
		Remark:     "",
	})

	glog.Info(ctx, "失败订单重试成功", g.Map{
		"orderId":   existingOrder.OrderId,
		"jdOrderId": jdOrderId,
		"cookieId":  cookieId,
	})

	return &model.CreateOrderResult{
		WxPayUrl:  wxPayUrl,
		JdOrderId: jdOrderId,
		OrderId:   existingOrder.OrderId,
	}, nil
}
