package jd_cookie

import (
	"context"
	"kami/internal/consts"
	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/utility/config"
	"kami/utility/integration/originalJd"
	"kami/utility/utils"
	"strings"
	"time"

	"github.com/duke-git/lancet/v2/convertor"
	"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"
)

// ====================================================================================
// 数据库查询辅助方法
// ====================================================================================

// getOrderByOrderId 根据订单号查询订单
func (s *sJdCookie) getOrderByOrderId(ctx context.Context, orderId string) (order *entity.V1JdCookieOrder, err error) {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	err = m.Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).Scan(&order)
	return
}

// getOrderByUserOrderId 根据用户订单号查询订单
func (s *sJdCookie) getOrderByUserOrderId(ctx context.Context, userOrderId string) (order *entity.V1JdCookieOrder, err error) {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	err = m.Where(dao.V1JdCookieOrder.Columns().UserOrderId, userOrderId).Scan(&order)
	err = utils.HandleNoRowsError(err)
	return
}

// getJdOrderByJdOrderId 根据京东订单号查询京东订单
func (s *sJdCookie) getJdOrderByJdOrderId(ctx context.Context, jdOrderId string) (jdOrder *entity.V1JdCookieJdOrder, err error) {
	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Scan(&jdOrder)
	return
}

// getCookieById 根据Cookie ID获取Cookie信息
func (s *sJdCookie) getCookieById(ctx context.Context, cookieId string) (cookie *entity.V1JdCookieAccount, err error) {
	m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())
	err = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Scan(&cookie)
	return
}

// ====================================================================================
// 数据库更新辅助方法
// ====================================================================================

// createJdOrderRecord 创建京东订单记录
func (s *sJdCookie) createJdOrderRecord(ctx context.Context, req *model.CreateJdOrderRecordReq) error {
	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	_, err := m.Insert(&do.V1JdCookieJdOrder{
		JdOrderId:     req.JdOrderId,
		RealJdOrderId: req.RealJdOrderId,
		PayId:         req.PayId,
		Amount:        req.Amount,
		Category:      req.Category,
		CookieId:      req.CookieId,
		Status:        int(consts.JdOrderStatusPending),
		WxPayUrl:      req.WxPayUrl,
		WxPayExpireAt: gtime.Now().Add(time.Minute * consts.WxPayUrlExpireDuration),
		OrderExpireAt: gtime.Now().Add(time.Hour * consts.JdOrderExpireDuration),
	})
	return err
}

// createOrderRecord 创建订单记录（带并发冲突处理）
func (s *sJdCookie) createOrderRecord(ctx context.Context, internalOrderId, userOrderId string, amount float64, category consts.RedeemOrderCardCategory, jdOrderId, wxPayUrl string) error {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())

	// 尝试插入订单记录
	_, err := m.Insert(&do.V1JdCookieOrder{
		OrderId:     internalOrderId,
		UserOrderId: userOrderId,
		Amount:      amount,
		Category:    category,
		JdOrderId:   jdOrderId,
		Status:      int(consts.OrderStatusCreated),
	})

	if err != nil {
		// 检查是否是唯一索引冲突错误（MySQL duplicate entry error）
		// 这里可以根据数据库类型调整错误检测逻辑
		if strings.Contains(strings.ToLower(err.Error()), "duplicate") {
			glog.Warning(ctx, "检测到重复订单，可能是并发创建导致", g.Map{
				"userOrderId":     userOrderId,
				"internalOrderId": internalOrderId,
				"error":           err,
			})
			return gerror.New("订单已存在，请勿重复创建")
		}

		// 其他类型的错误
		glog.Error(ctx, "创建订单记录失败", g.Map{
			"userOrderId":     userOrderId,
			"internalOrderId": internalOrderId,
			"error":           err,
		})
		return gerror.Wrap(err, "创建订单记录失败")
	}

	return nil
}

// updateOrderLastRequest 更新订单最后请求时间
func (s *sJdCookie) updateOrderLastRequest(ctx context.Context, orderId string) error {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	_, err := m.Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).Update(&do.V1JdCookieOrder{
		LastRequestAt: gtime.Now(),
	})
	return err
}

// updateOrderJdOrderId 更新订单关联的京东订单ID
func (s *sJdCookie) updateOrderJdOrderId(ctx context.Context, orderId, jdOrderId string) error {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	updateData := &do.V1JdCookieOrder{
		JdOrderId: jdOrderId,
	}
	// 注意：wxPayUrl 字段需要数据库表支持后才能使用
	// 暂时通过 WxPayUrl 字段存储在 jd_order 表中
	_, err := m.Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).Update(updateData)
	return err
}

// updateOrderFailure 更新订单失败信息
func (s *sJdCookie) updateOrderFailure(ctx context.Context, orderId string, status consts.OrderStatus) error {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	updateData := &do.V1JdCookieOrder{
		Status: int(status),
	}
	_, err := m.Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).Update(updateData)
	return err
}

// updateOrderSuccess 更新订单成功信息(从失败状态恢复)
func (s *sJdCookie) updateOrderSuccess(ctx context.Context, orderId, jdOrderId string) error {
	m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	updateData := &do.V1JdCookieOrder{
		JdOrderId: jdOrderId,
		Status:    int(consts.OrderStatusPending), // 恢复为待支付状态
	}
	glog.Info(ctx, "订单重试成功,恢复待支付状态", g.Map{
		"orderId":   orderId,
		"jdOrderId": jdOrderId,
	})
	_, err := m.Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).Update(updateData)
	return err
}

// updateJdOrderPaymentUrl 更新京东订单的支付链接
func (s *sJdCookie) updateJdOrderPaymentUrl(ctx context.Context, jdOrderId, wxPayUrl string) error {
	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取更新前的订单信息
	var oldOrder *entity.V1JdCookieJdOrder
	err := m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Scan(&oldOrder)
	if err != nil || oldOrder == nil {
		glog.Warning(ctx, "查询京东订单失败，无法记录历史", err)
		// 即使查询失败也继续更新
	}

	_, err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Update(&do.V1JdCookieJdOrder{
		WxPayUrl:      wxPayUrl,
		WxPayExpireAt: gtime.Now().Add(time.Minute * consts.WxPayUrlExpireDuration),
	})
	if err != nil {
		return err
	}

	// 记录支付链接更新历史
	if oldOrder != nil && oldOrder.WxPayUrl != wxPayUrl {
		_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeReplace, oldOrder.OrderId, wxPayUrl, "")
	}

	return err
}

// updateJdOrderId 更新京东订单关联的用户订单ID
func (s *sJdCookie) updateJdOrderId(ctx context.Context, jdOrderId, orderId string) error {
	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取更新前的京东订单信息
	var oldJdOrder *entity.V1JdCookieJdOrder
	err := m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Scan(&oldJdOrder)
	if err != nil || oldJdOrder == nil {
		glog.Warning(ctx, "查询京东订单失败，无法记录历史", err)
		// 即使查询失败也继续更新
	}

	// 更新订单ID
	_, err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Update(&do.V1JdCookieJdOrder{
		OrderId: orderId,
	})
	if err != nil {
		return err
	}

	// 记录订单绑定历史
	var changeType consts.JdOrderChangeType
	if oldJdOrder != nil {
		if oldJdOrder.OrderId == "" {
			changeType = consts.JdOrderChangeTypeBind // 首次绑定
		} else if oldJdOrder.OrderId != orderId {
			changeType = consts.JdOrderChangeTypeReplace // 更换绑定
		}
	} else {
		changeType = consts.JdOrderChangeTypeBind // 首次绑定
	}

	// 获取京东订单的支付链接
	wxPayUrl := ""
	if oldJdOrder != nil {
		wxPayUrl = oldJdOrder.WxPayUrl
	}
	_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, wxPayUrl, "")

	return err
}

// ====================================================================================
// 订单复用相关方法
// ====================================================================================

// findReusableJdOrder 查找可复用的京东订单
func (s *sJdCookie) findReusableJdOrder(ctx context.Context, amount float64, category consts.RedeemOrderCardCategory) (jdOrder *entity.V1JdCookieJdOrder, err error) {
	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())

	// 查找符合条件的京东订单：
	// 1. 金额和品类相同
	// 2. 状态为待支付
	// 3. 没有关联订单
	// 4. 订单未过期
	err = m.Where(dao.V1JdCookieJdOrder.Columns().Amount, amount).
		Where(dao.V1JdCookieJdOrder.Columns().Category, category).
		Where(dao.V1JdCookieJdOrder.Columns().Status, int(consts.JdOrderStatusPending)).
		WhereNull(dao.V1JdCookieJdOrder.Columns().OrderId).
		WhereGT(dao.V1JdCookieJdOrder.Columns().OrderExpireAt, gtime.Now()).
		OrderAsc(dao.V1JdCookieJdOrder.Columns().CreatedAt).
		Scan(&jdOrder)

	return
}

// ====================================================================================
// 京东接口调用方法
// ====================================================================================

// callJdCreateOrder 调用京东下单接口
func (s *sJdCookie) callJdCreateOrder(ctx context.Context, req *model.CallJdCreateOrderReq) (res *model.CallJdCreateOrderRes, err error) {
	res = &model.CallJdCreateOrderRes{
		IsCkError: false,
	}
	cookie, err := s.getCookieById(ctx, req.CookieId)
	if err != nil {
		return
	}
	appResp, err := originalJd.NewClient().AppleRecharge(ctx, &originalJd.AppleRechargeReq{
		FacePrice: req.Amount,
		Category:  req.Category,
		OrderId:   req.JdOrderId,
		Cookies:   cookie.CookieValue,
	})
	glog.Info(ctx, "下单接口返回", appResp)
	if err != nil {
		if appResp != nil {
			res.Remark = appResp.Msg
			if appResp.Code == consts.CardCookieJDStatusStockError || appResp.Code == consts.CardCookieJDStatusWrongFacePrice {
				res.IsStockError = true
			}
			if appResp.Code == consts.CardCookieJDStatusCkFailed {
				res.IsCkError = true
			}
		}

		if res.Remark == "" {
			res.Remark = err.Error()
		}
		return
	}
	res.Remark = appResp.Msg
	if appResp.Code != consts.CardCookieJDStatusSuccess || appResp.Deeplink == "" {
		return res, gerror.New("下单失败，" + appResp.Msg)
	}
	res = &model.CallJdCreateOrderRes{
		RealJdOrderId: appResp.OrderId, // 京东客户端返回的真实订单ID
		PayId:         appResp.PayId,
		WxPayUrl:      appResp.Deeplink,
		Remark:        appResp.Msg,
	}
	return
}

// refreshPaymentUrl 刷新支付链接
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, req *model.RefreshPaymentUrlReq) (wxPayUrl string, isCkFailed bool, err error) {
	cookie, err := s.getCookieById(ctx, req.CookieId)
	if err != nil {
		return
	}
	jdOrder, err := s.getJdOrderByJdOrderId(ctx, req.JdOrderId)
	if err != nil {
		return
	}
	jdOrderInt, _ := convertor.ToInt(jdOrder.RealJdOrderId)

	appResp, err := originalJd.NewClient().RefreshPayment(ctx, &originalJd.RefreshPaymentReq{
		Cookies:     cookie.CookieValue,
		OrderId:     jdOrderInt,
		PayId:       req.PayId,
		UserOrderId: req.JdOrderId,
	})

	glog.Info(ctx, "刷新支付链接", g.Map{
		"appResp":   appResp,
		"cookie":    cookie,
		"jdOrderId": req.JdOrderId,
	})
	if err != nil {
		return
	}
	if appResp.Code == consts.CardCookieJDStatusExpired {
		return "", true, gerror.New(appResp.Msg)
	}
	if appResp.Code != consts.CardCookieJDStatusSuccess || appResp.Deeplink == "" {
		return "", false, gerror.New("刷新链接，" + appResp.Msg)
	}
	wxPayUrl = appResp.Deeplink
	return
}

// callJdCheckPayment 调用京东接口检查支付状态
func (s *sJdCookie) callJdCheckPayment(ctx context.Context, req *model.CallJdCheckPaymentReq) (*originalJd.AppleRechargeCardInfoResp, error) {
	// 创建京东客户端
	client := originalJd.NewClient()

	// 调用检查支付状态接口，使用京东客户端返回的真实订单ID
	appReq := &originalJd.AppleRechargeCardInfoReq{
		OrderId:   req.JdOrderId,
		JdOrderId: req.RealJdOrderId,
		Cookies:   req.CookieValue,
		Category:  req.Category,
	}

	resp, err := client.GetCardInfo(ctx, appReq)
	if err != nil {
		return resp, err
	}
	return resp, nil
}

// validateCookieWithCheckPayment 使用callJdCheckPayment验证Cookie
func (s *sJdCookie) validateCookieWithCheckPayment(ctx context.Context, cookieValue string) error {
	glog.Info(ctx, "开始使用CheckPayment接口验证Cookie有效性")

	// 创建一个模拟的检查支付状态请求
	req := &model.CallJdCheckPaymentReq{
		JdOrderId:     "validation_test_" + utils.GenerateRandomUUID()[:8], // 生成一个测试订单ID
		RealJdOrderId: "339328433580",
		CookieValue:   cookieValue,
		Category:      consts.RedeemOrderCardCategoryCTrip, // 使用Apple分类作为默认
	}

	resp, _ := s.callJdCheckPayment(ctx, req)

	// 检查是否返回了IsCkFailed=true
	if resp != nil && resp.IsCkFailed {
		glog.Error(ctx, "Cookie验证失败，IsCkFailed=true", resp)
		return gerror.New("Cookie已失效，无法使用")
	}

	glog.Info(ctx, "Cookie验证成功")
	return nil
}

// ====================================================================================
// Cookie处理方法
// ====================================================================================

// handleCookieFailure 处理Cookie失败
func (s *sJdCookie) handleCookieFailure(ctx context.Context, userOrderId, cookieId, orderId string, isCKFailed bool, remark string) {
	// 获取当前Cookie信息
	m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())
	var account *entity.V1JdCookieAccount
	err := m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Scan(&account)
	if err != nil || account == nil {
		return
	}

	newFailureCount := account.FailureCount + 1
	statusBefore := consts.JdCookieStatus(account.Status)
	var statusAfter consts.JdCookieStatus

	if newFailureCount >= consts.JdCookieMaxFailureCount || isCKFailed {
		// 失败次数过多，标记为失效
		statusAfter = consts.JdCookieStatusExpired
		_, _ = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Update(&do.V1JdCookieAccount{
			Status:       int(statusAfter),
			FailureCount: newFailureCount,
		})
	} else {
		// 暂停Cookie
		statusAfter = consts.JdCookieStatusSuspend
		suspendUntil := gtime.Now().Add(time.Minute * consts.JdCookieSuspendDuration)
		_, _ = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Update(&do.V1JdCookieAccount{
			Status:       int(statusAfter),
			FailureCount: newFailureCount,
			SuspendUntil: suspendUntil,
		})
	}

	// 记录失败历史
	_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
		CookieId:     cookieId,
		ChangeType:   consts.CookieChangeTypeFail,
		StatusBefore: statusBefore,
		StatusAfter:  statusAfter,
		OrderId:      orderId,
		UserOrderId:  userOrderId,
		FailureCount: newFailureCount,
		Remark:       remark,
	})
}
