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/utils"
	"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"
)

// ====================================================================================
// Cookie轮询分配相关方法
// ====================================================================================

// GetAvailableCookie 获取可用的Cookie（轮询分配）
func (s *sJdCookie) GetAvailableCookie(ctx context.Context) (cookieId string, err error) {
	// 首先尝试解锁过期的暂停Cookie
	s.unlockExpiredCookies(ctx)

	// 获取所有可用的Cookie
	m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())
	var availableCookies []*entity.V1JdCookieAccount
	err = m.Where(dao.V1JdCookieAccount.Columns().Status, int(consts.JdCookieStatusNormal)).
		OrderAsc(dao.V1JdCookieAccount.Columns().LastUsedAt).
		Scan(&availableCookies)
	if err != nil {
		return "", gerror.Wrap(err, "查询可用Cookie失败")
	}

	if len(availableCookies) == 0 {
		return "", gerror.New(consts.ErrCodeCookieNotAvailable)
	}

	// 选择最久未使用的Cookie
	selectedCookie := availableCookies[0]

	// 更新最后使用时间
	_, err = m.Where(dao.V1JdCookieAccount.Columns().CookieId, selectedCookie.CookieId).
		Update(&do.V1JdCookieAccount{
			LastUsedAt: gtime.Now(),
		})
	if err != nil {
		glog.Error(ctx, "更新Cookie最后使用时间失败", err)
	}

	return selectedCookie.CookieId, nil
}

// unlockExpiredCookies 解锁过期的暂停Cookie
func (s *sJdCookie) unlockExpiredCookies(ctx context.Context) {
	m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())

	// 先查询即将解锁的Cookie，用于记录历史
	var expiredCookies []*entity.V1JdCookieAccount
	err := m.Where(dao.V1JdCookieAccount.Columns().Status, int(consts.JdCookieStatusSuspend)).
		WhereLTE(dao.V1JdCookieAccount.Columns().SuspendUntil, gtime.Now()).
		WhereNotNull(dao.V1JdCookieAccount.Columns().SuspendUntil).
		Scan(&expiredCookies)
	if err != nil {
		glog.Error(ctx, "查询过期暂停Cookie失败", err)
		return
	}

	// 批量解锁暂停时间已过的Cookie
	_, err = m.Where(dao.V1JdCookieAccount.Columns().Status, int(consts.JdCookieStatusSuspend)).
		WhereLTE(dao.V1JdCookieAccount.Columns().SuspendUntil, gtime.Now()).
		WhereNotNull(dao.V1JdCookieAccount.Columns().SuspendUntil).
		Update(&do.V1JdCookieAccount{
			Status:       int(consts.JdCookieStatusNormal),
			SuspendUntil: nil,
		})
	if err != nil {
		glog.Error(ctx, "解锁暂停Cookie失败", err)
		return
	}

	// 为每个解锁的Cookie记录历史
	for _, cookie := range expiredCookies {
		_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
			CookieId:     cookie.CookieId,
			ChangeType:   consts.CookieChangeTypeResume,
			StatusBefore: consts.JdCookieStatusSuspend,
			StatusAfter:  consts.JdCookieStatusNormal,
			OrderId:      "",
			FailureCount: cookie.FailureCount,
			Remark:       "自动解锁过期暂停Cookie",
		})
	}

	if len(expiredCookies) > 0 {
		glog.Info(ctx, "自动解锁过期暂停Cookie", g.Map{
			"unlockedCount": len(expiredCookies),
		})
	}
}

// ====================================================================================
// Cookie状态管理相关方法
// ====================================================================================

// UpdateCookieStatus 更新Cookie状态
func (s *sJdCookie) UpdateCookieStatus(ctx context.Context, cookieId string, status consts.JdCookieStatus, failureCount int, remark string) (err error) {
	if cookieId == "" {
		return gerror.New("Cookie ID不能为空")
	}

	m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取更新前的Cookie信息
	var oldCookie *entity.V1JdCookieAccount
	err = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Scan(&oldCookie)
	if err != nil {
		return gerror.Wrap(err, "查询Cookie信息失败")
	}
	if oldCookie == nil {
		return gerror.New("Cookie不存在")
	}

	updateData := &do.V1JdCookieAccount{
		Status:       int(status),
		FailureCount: failureCount,
	}

	// 如果是暂停状态，设置暂停时间
	if status == consts.JdCookieStatusSuspend {
		updateData.SuspendUntil = gtime.Now().Add(time.Minute * consts.JdCookieSuspendDuration)
	}

	// 如果是恢复正常状态，清除暂停时间
	if status == consts.JdCookieStatusNormal {
		updateData.SuspendUntil = nil
	}

	_, err = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Update(updateData)
	if err != nil {
		return gerror.Wrap(err, "更新Cookie状态失败")
	}

	// 确定变更类型
	var changeType consts.CookieChangeType
	switch status {
	case consts.JdCookieStatusNormal:
		changeType = consts.CookieChangeTypeResume
	case consts.JdCookieStatusSuspend:
		changeType = consts.CookieChangeTypeSuspend
	case consts.JdCookieStatusExpired:
		changeType = consts.CookieChangeTypeFail
	default:
		changeType = consts.CookieChangeTypeUpdate
	}

	// 记录状态变更历史
	_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
		CookieId:     cookieId,
		ChangeType:   changeType,
		StatusBefore: consts.JdCookieStatus(oldCookie.Status),
		StatusAfter:  status,
		OrderId:      "",
		FailureCount: failureCount,
		Remark:       remark,
	})

	return
}

// ====================================================================================
// 京东订单管理相关方法
// ====================================================================================

// CreateJdOrder 创建京东订单
func (s *sJdCookie) CreateJdOrder(ctx context.Context, jdOrderId, payId, cookieId, category string, amount float64) (err error) {
	if jdOrderId == "" || payId == "" || cookieId == "" {
		return gerror.New("京东订单参数不能为空")
	}

	m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())
	_, err = m.Insert(&do.V1JdCookieJdOrder{
		JdOrderId:     jdOrderId,
		PayId:         payId,
		Amount:        amount,
		Category:      category,
		CookieId:      cookieId,
		Status:        int(consts.JdOrderStatusPending),
		OrderExpireAt: gtime.Now().Add(time.Hour * consts.JdOrderExpireDuration),
	})

	if err != nil {
		return gerror.Wrap(err, "创建京东订单失败")
	}

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

	return
}

// UpdateJdOrderStatus 更新京东订单状态
func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string, remark string) (err error) {
	if jdOrderId == "" {
		return gerror.New("京东订单号不能为空")
	}

	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 {
		return gerror.Wrap(err, "查询京东订单失败")
	}
	if oldOrder == nil {
		return gerror.New("京东订单不存在")
	}

	updateData := &do.V1JdCookieJdOrder{
		Status: int(status),
	}

	if wxPayUrl != "" {
		updateData.WxPayUrl = wxPayUrl
		updateData.WxPayExpireAt = gtime.Now().Add(time.Minute * consts.WxPayUrlExpireDuration)
	}

	_, err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Update(updateData)
	if err != nil {
		return gerror.Wrap(err, "更新京东订单状态失败")
	}

	// 记录状态变更历史
	if oldOrder.Status != int(status) {
		var changeType consts.JdOrderChangeType
		switch status {
		case consts.JdOrderStatusPaid:
			changeType = consts.JdOrderChangeTypePay
		case consts.JdOrderStatusExpired:
			changeType = consts.JdOrderChangeTypeExpire
		case consts.JdOrderStatusCanceled:
			changeType = consts.JdOrderChangeTypeInvalid
		case consts.JdOrderStatusCkFailed:
			changeType = consts.JdOrderChangeTypeInvalid
		case consts.JdOrderStatusPending:
			changeType = consts.JdOrderChangeTypePendPay
		case consts.JdOrderStatusSent:
			changeType = consts.JdOrderChangeTypeSend
		}

		// 获取关联的订单ID
		orderId := oldOrder.OrderId

		payUrl := wxPayUrl
		if payUrl == "" {
			payUrl = oldOrder.WxPayUrl
		}
		_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, payUrl, remark)
	}

	return
}

// ====================================================================================
// 历史记录相关方法
// ====================================================================================

// RecordCookieHistory 记录Cookie变更历史
func (s *sJdCookie) RecordCookieHistory(ctx context.Context, req *model.RecordCookieHistoryReq) (err error) {
	m := dao.V1JdCookieChangeHistory.Ctx(ctx).DB(config.GetDatabaseV1())

	historyUuid := utils.GenerateRandomUUID()
	_, err = m.Insert(&do.V1JdCookieChangeHistory{
		HistoryUuid:  historyUuid,
		CookieId:     req.CookieId,
		ChangeType:   req.ChangeType,
		StatusBefore: int(req.StatusBefore),
		StatusAfter:  int(req.StatusAfter),
		OrderId:      req.OrderId,
		UserOrderId:  req.UserOrderId,
		FailureCount: req.FailureCount,
		Remark:       req.Remark,
	})

	if err != nil {
		glog.Error(ctx, "记录Cookie变更历史失败", g.Map{
			"cookieId":     req.CookieId,
			"changeType":   req.ChangeType,
			"statusBefore": req.StatusBefore,
			"statusAfter":  req.StatusAfter,
			"orderId":      req.OrderId,
			"failureCount": req.FailureCount,
			"remark":       req.Remark,
			"error":        err,
		})
	}

	return
}

// RecordJdOrderHistory 记录京东订单变更历史
func (s *sJdCookie) RecordJdOrderHistory(ctx context.Context, jdOrderId string, changeType consts.JdOrderChangeType, orderId, wxPayUrl, remark string) (err error) {
	m := dao.V1JdCookieJdOrderChangeHistory.Ctx(ctx).DB(config.GetDatabaseV1())

	_, err = m.Insert(&do.V1JdCookieJdOrderChangeHistory{
		HistoryUuid: utils.GenerateRandomUUID(),
		JdOrderId:   jdOrderId,
		ChangeType:  changeType,
		OrderId:     orderId,
		WxPayUrl:    wxPayUrl,
		Remark:      remark,
	})

	if err != nil {
		glog.Error(ctx, "记录京东订单变更历史失败", g.Map{
			"jdOrderId":  jdOrderId,
			"changeType": changeType,
			"orderId":    orderId,
			"error":      err,
		})
	}

	return
}

// RecordOrderHistory 记录订单变更历史
func (s *sJdCookie) RecordOrderHistory(ctx context.Context, req *model.RecordOrderHistoryReq) (err error) {
	m := dao.V1JdCookieOrderChangeHistory.Ctx(ctx).DB(config.GetDatabaseV1())

	historyUuid := utils.GenerateRandomUUID()
	_, err = m.Insert(&do.V1JdCookieOrderChangeHistory{
		HistoryUuid: historyUuid,
		OrderId:     req.OrderId,
		ChangeType:  req.ChangeType,
		JdOrderId:   req.JdOrderId,
		Remark:      req.Remark,
	})

	if err != nil {
		glog.Error(ctx, "记录订单变更历史失败", g.Map{
			"orderId":    req.OrderId,
			"changeType": req.ChangeType,
			"jdOrderId":  req.JdOrderId,
			"error":      err,
		})
	}

	return
}
