package camel_oil

import (
	"context"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/shopspring/decimal"
	"kami/internal/model"
	"kami/utility/utils"

	"kami/internal/consts"
	"kami/internal/dao"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"
	"kami/utility/integration/camel_oil_api"
)

// ====================================================================================
// Token 管理相关方法
// ====================================================================================

// CreateToken 创建 Token
func (s *sCamelOil) CreateToken(ctx context.Context, req *model.CamelOilTokenCreateInput) (tokenId int64, err error) {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取当前用户信息
	_, userInfo, err := service.SysUser().GetUserFromToken(ctx)
	if err != nil {
		return 0, gerror.Wrap(err, "获取用户信息失败")
	}

	var userId string
	if userInfo != nil && userInfo.Id != "" {
		userId = userInfo.Id
	} else {
		return 0, gerror.NewCode(gcode.CodeNotAuthorized, "权限不足")
	}

	// 将 float64 转换为 decimal.Decimal 存储到数据库
	rechargeLimitAmountDecimal := decimal.NewFromFloat(req.RechargeLimitAmount)
	isOk, err := camel_oil_api.NewClient(ctx).SendCaptcha(ctx, req.Phone)
	if !isOk {
		return 0, gerror.NewCode(gcode.CodeBusinessValidationFailed, "验证码发送失败")
	}
	result, err := m.Insert(&do.V1CamelOilToken{
		UserId:              userId,
		Name:                req.Name,
		Phone:               req.Phone,
		Status:              consts.CamelOilTokenStatusCodeSent,
		BindCount:           0,
		TotalBindAmount:     decimal.Zero,
		TotalRechargeAmount: decimal.Zero,
		RechargeLimitAmount: rechargeLimitAmountDecimal,
		RechargeLimitCount:  req.RechargeLimitCount,
		Remark:              req.Remark,
	})

	if err != nil {
		return 0, gerror.Wrap(err, "创建 Token失败")
	}

	tokenId, _ = result.LastInsertId()
	return tokenId, nil
}

// GetTokenInfo 获取 Token 信息
func (s *sCamelOil) GetTokenInfo(ctx context.Context, req *model.CamelOilTokenQueryInput) (token *entity.V1CamelOilToken, err error) {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
	if err != nil {
		return nil, gerror.Wrap(err, "查询Token信息失败")
	}
	if token == nil {
		return nil, gerror.New("Token不存在")
	}

	// 权限检查：普通用户只能查看自己的token
	needAuth, userInfo, err := service.SysUser().GetUserFromToken(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取用户信息失败")
	}

	// 如果是普通用户且token不属于当前用户，拒绝访问
	if needAuth && userInfo != nil && userInfo.Id != "" && token.UserId != userInfo.Id {
		return nil, gerror.NewCode(gcode.CodeNotAuthorized, "无权访问此Token")
	}

	return token, nil
}

// ListTokens 列出所有可用的 Token
func (s *sCamelOil) ListTokens(ctx context.Context) (tokens []*entity.V1CamelOilToken, err error) {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	err = m.Where(dao.V1CamelOilToken.Columns().Status, consts.CamelOilTokenStatusAvailable).
		OrderAsc(dao.V1CamelOilToken.Columns().LastUsedAt).
		OrderAsc(dao.V1CamelOilToken.Columns().LastBindAt).
		Scan(&tokens)
	if err != nil {
		return nil, gerror.Wrap(err, "查询Token列表失败")
	}

	return tokens, nil
}

// ListTokensWithPagination 列出所有可用的 Token（支持分页和查询条件）
func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, req *model.CamelOilTokenListInput) (tokens []*entity.V1CamelOilToken, total int, err error) {
	query := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取当前用户信息
	needAuth, userInfo, _ := service.SysUser().GetUserFromToken(ctx)

	// 如果是普通用户（非管理员），只能查看自己的token
	if needAuth && userInfo != nil && userInfo.Id != "" {
		query = query.Where(dao.V1CamelOilToken.Columns().UserId, userInfo.Id)
	}
	// 管理员或不需要认证的情况可以查看所有token（包括user_id为空的token）

	// 添加查询条件
	if req.Name != "" {
		query = query.WhereLike(dao.V1CamelOilToken.Columns().Name, utils.OrmLike(req.Name))
	}

	if req.Status > 0 {
		query = query.Where(dao.V1CamelOilToken.Columns().Status, req.Status)
	}

	// 获取总数
	totalCount, err := query.Count()
	if err != nil {
		return nil, 0, gerror.Wrap(err, "查询Token总数失败")
	}

	// 分页查询
	err = query.
		Offset((req.Current - 1) * req.PageSize).
		Limit(req.PageSize).
		OrderDesc(dao.V1CamelOilToken.Columns().CreatedAt).
		Scan(&tokens)

	if err != nil {
		return nil, 0, gerror.Wrap(err, "查询Token列表失败")
	}

	return tokens, totalCount, nil
}

// GetOptimalTokenForBinding 获取最优Token用于绑卡（按上传时间顺序选择）
func (s *sCamelOil) GetOptimalTokenForBinding(ctx context.Context, amount decimal.Decimal) (*entity.V1CamelOilToken, error) {
	// 获取所有普通用户上传的可用的Token（按上传时间顺序，最早上传的在前）
	var tokens []*entity.V1CamelOilToken
	err := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1CamelOilToken.Columns().Status, consts.CamelOilTokenStatusAvailable).
		WhereNot(dao.V1CamelOilToken.Columns().UserId, ""). // 只获取普通用户上传的Token（UserId不为空）
		OrderAsc(dao.V1CamelOilToken.Columns().CreatedAt).  // 按上传时间排序，最早上传的在前
		Scan(&tokens)

	if err != nil {
		return nil, gerror.Wrap(err, "查询Token列表失败")
	}

	if len(tokens) == 0 {
		return nil, gerror.New("没有可用的用户Token")
	}

	// 按上传时间顺序筛选第一个符合条件的Token
	for _, token := range tokens {
		if s.isTokenEligible(ctx, token, amount) {
			glog.Infof(ctx, "按上传时间顺序选择用户Token: tokenId=%d, phone=%s, name=%s, userId=%s, 金额=%.2f",
				token.Id, token.Phone, token.Name, token.UserId, amount.InexactFloat64())
			return token, nil
		}
	}

	return nil, gerror.New("没有符合条件的用户Token")
}

// isTokenEligible 检查Token是否符合使用条件（简化版）
func (s *sCamelOil) isTokenEligible(ctx context.Context, token *entity.V1CamelOilToken, amount decimal.Decimal) bool {
	// 基本状态检查
	if token.Status != int(consts.CamelOilTokenStatusAvailable) {
		return false
	}

	// 检查Token有效性（是否过期）
	if token.LoginTokenExpiresAt != nil && token.LoginTokenExpiresAt.Before(gtime.Now()) {
		return false
	}

	// 检查充值限制：总绑卡数量或金额任一超过限制就停止调度
	// 1. 充值金额限制检查（检查本次充值后是否会超过限制）
	if token.RechargeLimitAmount.Cmp(decimal.Zero) > 0 {
		newTotalAmount := token.TotalBindAmount.Add(amount)
		if newTotalAmount.Cmp(token.RechargeLimitAmount) > 0 {
			glog.Debugf(ctx, "Token本次充值后将超限，tokenId=%d, 已充值=%.2f, 本次=%.2f, 合计=%.2f, 限制=%.2f",
				token.Id, token.TotalBindAmount.InexactFloat64(), amount.InexactFloat64(),
				newTotalAmount.InexactFloat64(), token.RechargeLimitAmount.InexactFloat64())
			return false
		}
	}

	// 2. 充值次数限制检查
	if token.RechargeLimitCount > 0 {
		if token.BindCount >= token.RechargeLimitCount {
			glog.Debugf(ctx, "Token充值次数已达上限，tokenId=%d, 已使用=%d, 限制=%d",
				token.Id, token.BindCount, token.RechargeLimitCount)
			return false
		}
	}

	// 获取用户余额信息和状态检查
	if token.UserId != "" {
		// 1. 检查用户状态是否正常
		isNormal, err := service.SysUser().CheckUserNormal(ctx, token.UserId)
		if err != nil {
			glog.Warningf(ctx, "检查用户状态失败，userId=%s: %v", token.UserId, err)
			return false
		}
		if !isNormal {
			glog.Debugf(ctx, "用户状态异常，userId=%s", token.UserId)
			return false
		}

		// 2. 检查用户余额是否充足
		isEnough, err := service.SysUserPayment().CheckBalanceEnough(ctx, &model.SysUserPaymentCheckBalanceInput{
			UserId: token.UserId,
			Amount: amount,
		})
		if err != nil {
			glog.Warningf(ctx, "检查用户余额失败，userId=%s: %v", token.UserId, err)
			return false
		}
		if !isEnough {
			glog.Debugf(ctx, "用户余额不足，userId=%s, 金额=%.2f", token.UserId, amount.InexactFloat64())
			return false
		}
	}

	return true
}

// UpdateTokenInfo 修改 Token 基本信息（不包括 tokenValue）
func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, req *model.CamelOilTokenUpdateInput) error {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	// 权限检查：获取token信息验证所有权
	var token *entity.V1CamelOilToken
	err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
	if err != nil {
		return gerror.Wrap(err, "查询Token信息失败")
	}
	if token == nil {
		return gerror.New("Token不存在")
	}

	// 权限检查：普通用户只能修改自己的token
	needAuth, userInfo, err := service.SysUser().GetUserFromToken(ctx)
	if err != nil {
		return gerror.Wrap(err, "获取用户信息失败")
	}

	// 如果是普通用户且token不属于当前用户，拒绝修改
	if needAuth && userInfo != nil && userInfo.Id != "" && token.UserId != userInfo.Id {
		return gerror.NewCode(gcode.CodeNotAuthorized, "无权修改此Token")
	}

	// 将 float64 转换为 decimal.Decimal 存储到数据库
	rechargeLimitAmountDecimal := decimal.NewFromFloat(req.RechargeLimitAmount)

	_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
		Name:                req.Name,
		Remark:              req.Remark,
		RechargeLimitAmount: rechargeLimitAmountDecimal,
		RechargeLimitCount:  req.RechargeLimitCount,
	})

	if err != nil {
		return gerror.Wrap(err, "修改Token信息失败")
	}

	glog.Infof(ctx, "Token信息修改成功: tokenId=%d, tokenName=%s", req.TokenId, req.Name)
	return nil
}

// DeleteToken 删除 Token（软删除）
func (s *sCamelOil) DeleteToken(ctx context.Context, req *model.CamelOilTokenDeleteInput) error {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	// 权限检查：获取token信息验证所有权
	var token *entity.V1CamelOilToken
	err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
	if err != nil {
		return gerror.Wrap(err, "查询Token信息失败")
	}
	if token == nil {
		return gerror.New("Token不存在")
	}

	// 权限检查：普通用户只能删除自己的token
	needAuth, userInfo, err := service.SysUser().GetUserFromToken(ctx)
	if err != nil {
		return gerror.Wrap(err, "获取用户信息失败")
	}

	// 如果是普通用户且token不属于当前用户，拒绝删除
	if needAuth && userInfo != nil && userInfo.Id != "" && token.UserId != userInfo.Id {
		return gerror.NewCode(gcode.CodeNotAuthorized, "无权删除此Token")
	}

	_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Delete()

	if err != nil {
		return gerror.Wrap(err, "删除Token失败")
	}

	glog.Infof(ctx, "Token删除成功: tokenId=%d", req.TokenId)
	return nil
}

// UpdateTokenStatus 更新 Token 状态并记录日志
func (s *sCamelOil) UpdateTokenStatus(ctx context.Context, req *model.CamelOilTokenStatusUpdateInput) error {
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())

	// 获取当前 Token 信息
	var token *entity.V1CamelOilToken
	err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
	if err != nil {
		return gerror.Wrap(err, "查询Token失败")
	}
	if token == nil {
		return gerror.New("Token不存在")
	}

	oldStatus := consts.CamelOilTokenStatus(token.Status)

	// 如果状态没有变化，则不更新
	if oldStatus == req.NewStatus {
		return nil
	}

	// 更新 Token 状态
	_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
		Status: int(req.NewStatus),
		Remark: req.Remark,
	})

	if err != nil {
		return gerror.Wrap(err, "更新Token状态失败")
	}

	glog.Infof(ctx, "Token状态更新成功: tokenId=%d, 原状态=%s, 新状态=%s, 备注=%s", req.TokenId, consts.CamelOilTokenStatusText[oldStatus], consts.CamelOilTokenStatusText[req.NewStatus], req.Remark)
	return nil
}

// ====================================================================================
// 卡密绑定相关方法
// ====================================================================================

// BindCardToToken 绑定卡密到 Token（使用智能调度算法选择 Token）
func (s *sCamelOil) BindCardToToken(ctx context.Context, req *model.CamelOilCardBindInput) (bindingId int64, err error) {
	orderId := req.OrderId
	cardNumber := req.CardNumber
	cardPassword := req.CardPassword
	amount := req.Amount

	// 1. 获取订单信息
	var order *entity.V1CamelOilOrder
	err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1CamelOilOrder.Columns().Id, orderId).
		Scan(&order)
	if err != nil {
		return 0, gerror.Wrap(err, "查询订单失败")
	}
	if order == nil {
		return 0, gerror.New("订单不存在")
	}

	// 2. 使用智能调度算法选择最优 Token
	selectedToken, err := s.GetOptimalTokenForBinding(ctx, amount)
	if err != nil {
		return 0, gerror.Wrap(err, "获取可用Token失败")
	}
	if selectedToken == nil {
		return 0, gerror.New("没有符合条件的Token")
	}

	// 4.2 调用绑卡接口（使用选中 Token 的 LoginToken）
	rechargeErrType, rechargeErr := camel_oil_api.NewClient(ctx).RechargeCard(ctx, selectedToken.LoginToken, selectedToken.Phone, cardPassword)
	if rechargeErr != nil {
		switch rechargeErrType {
		case camel_oil_api.RechargeCardErrorCode:
			// 卡密错误：标记订单为绑定失败
			glog.Warningf(ctx, "卡密错误: %v", rechargeErr)
			// 调用已实现的方法更新订单状态
			_ = s.UpdateOrderStatus(ctx, orderId, consts.CamelOilOrderStatusFailed, consts.CamelOilOrderChangeTypeFail, "", "卡密样检失败")
			return 0, gerror.Wrap(rechargeErr, "卡密样检失败")
		case camel_oil_api.RechargeCardBannedOneDay:
			_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
				TokenId:   selectedToken.Id,
				NewStatus: consts.CamelOilTokenStatusDisabled,
				Remark:    "输错过于频繁，Token被封禁",
			})
			return 0, gerror.Wrap(rechargeErr, "输错过于频繁，Token被封禁")
		case camel_oil_api.RechargeCardErrorToken:
			// Token 过期/无效：标记 Token 为已过期
			glog.Warningf(ctx, "Token 过期: %v", rechargeErr)
			// 调用已实现的方法更新 Token 状态
			_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
				TokenId:   selectedToken.Id,
				NewStatus: consts.CamelOilTokenStatusExpired,
				Remark:    "Token已过期",
			})
			return 0, gerror.Wrap(rechargeErr, "Token过期，需要重新登录")
		default:
			// 网络或其他错误：不更新状态，由定时任务重试
			glog.Errorf(ctx, "绑卡失败（网络或其他错误）: %v", rechargeErr)
			return 0, gerror.Wrap(rechargeErr, "绑卡操作失败，稍后重试")
		}
	}

	// 5. 创建绑定记录
	bindingResult, err := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1()).
		Insert(&do.V1CamelOilCardBinding{
			TokenId:      selectedToken.Id,
			OrderId:      orderId,
			CardNumber:   cardNumber,
			CardPassword: cardPassword,
			Amount:       amount,
		})

	if err != nil {
		return 0, gerror.Wrap(err, "创建绑定记录失败")
	}

	bindingId, _ = bindingResult.LastInsertId()

	_, _ = dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1CamelOilToken.Columns().Id, selectedToken.Id).
		Data(dao.V1CamelOilToken.Columns().TotalBindAmount, &gdb.Counter{
			Field: dao.V1CamelOilToken.Columns().TotalBindAmount,
			Value: gconv.Float64(amount),
		}, dao.V1CamelOilToken.Columns().BindCount, &gdb.Counter{
			Field: dao.V1CamelOilToken.Columns().BindCount,
			Value: gconv.Float64(amount),
		}, dao.V1CamelOilToken.Columns().LastBindAt, gtime.Now(), dao.V1CamelOilToken.Columns().LastUsedAt, gtime.Now()).Update()

	//给商户加宽
	_, _ = service.SysUserPayment().Consumption(ctx, &model.SysUserPaymentRechargeOrConsumeInput{
		UserId:          selectedToken.UserId,
		OrderNo:         gconv.String(orderId),
		Amount:          amount,
		Remark:          "核销扣款",
		TransactionType: consts.UserPaymentRecordStatusConsume,
		Category:        consts.CardRedeemAccountCategoryCamelOil,
	}, nil)

	glog.Infof(ctx, "卡密绑定成功: bindingId=%d, tokenId=%d, 订单ID=%d, 绑定金额=%.2f",
		bindingId, selectedToken.Id, orderId, amount.InexactFloat64())

	return bindingId, nil
}

// GetCardBindingInfo 获取卡密绑定信息
func (s *sCamelOil) GetCardBindingInfo(ctx context.Context, bindingId int64) (binding *entity.V1CamelOilCardBinding, err error) {
	m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())

	err = m.Where(dao.V1CamelOilCardBinding.Columns().Id, bindingId).Scan(&binding)
	if err != nil {
		return nil, gerror.Wrap(err, "查询绑定信息失败")
	}
	if binding == nil {
		return nil, gerror.New("绑定记录不存在")
	}

	return binding, nil
}

// GetCardBindingByOrder 获取订单绑定的卡密信息
func (s *sCamelOil) GetCardBindingByOrder(ctx context.Context, orderId int64) (binding *entity.V1CamelOilCardBinding, err error) {
	m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())

	err = m.Where(dao.V1CamelOilCardBinding.Columns().OrderId, orderId).Scan(&binding)
	if err != nil {
		return nil, gerror.Wrap(err, "查询绑定信息失败")
	}

	return binding, nil
}

// GetCardBindingsByToken 根据 tokenId 查询绑定的卡密信息
func (s *sCamelOil) GetCardBindingsByToken(ctx context.Context, req *model.CamelOilCardListInput) (bindings []*entity.V1CamelOilCardBinding, total int, err error) {
	m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())

	// 权限检查：获取token信息验证所有权
	token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
	if err != nil {
		return nil, 0, err // GetTokenInfo已经包含权限检查
	}
	if token == nil {
		return nil, 0, gerror.New("Token不存在")
	}

	count, err := m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, req.TokenId).Count()
	if err != nil {
		return nil, 0, gerror.Wrap(err, "查询绑定记录计数失败")
	}

	err = m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, req.TokenId).
		Page(req.Current, req.PageSize).
		Scan(&bindings)
	if err != nil {
		return nil, 0, gerror.Wrap(err, "查询绑定记录失败")
	}

	return bindings, count, nil
}

// GetTokenBindingStats 获取 Token 的绑定统计
func (s *sCamelOil) GetTokenBindingStats(ctx context.Context, tokenId int64) (bindCount int, totalAmount decimal.Decimal, err error) {
	m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())

	var stats struct {
		BindCount   int
		TotalAmount decimal.Decimal
	}

	err = m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, tokenId).
		Fields("COUNT(*) as bind_count, SUM(amount) as total_amount").
		Scan(&stats)

	if err != nil {
		return 0, decimal.Zero, gerror.Wrap(err, "查询Token绑定统计失败")
	}

	return stats.BindCount, stats.TotalAmount, nil
}

// CalculateTotalBindingAmount 计算所有 Token 的累计绑定金额
func (s *sCamelOil) CalculateTotalBindingAmount(ctx context.Context) (totalAmount decimal.Decimal, err error) {
	m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())

	var result struct {
		Total decimal.Decimal
	}

	err = m.Fields("SUM(amount) as total").Scan(&result)
	if err != nil {
		return decimal.Zero, gerror.Wrap(err, "计算累计绑定金额失败")
	}

	return result.Total, nil
}

// InputVerificationCode 输入验证码
func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelOilTokenLoginInput) (string, error) {
	// 获取 Token 信息
	token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
	if err != nil {
		return "", gerror.Wrap(err, "查询Token信息失败")
	}

	if token == nil {
		return "", gerror.New("Token不存在")
	}

	// 检查 Token 状态，只有验证码已发送或验证失败的 Token 才能输入验证码
	if token.Status != int(consts.CamelOilTokenStatusCodeSent) && token.Status != int(consts.CamelOilTokenStatusVerificationFailed) {
		return "", gerror.New("Token状态不允许输入验证码")
	}

	client := camel_oil_api.NewClient(ctx)

	// 使用验证码登录
	loginToken, err := client.LoginWithCaptcha(ctx, token.Phone, req.Code)
	if err != nil {
		return "", gerror.Wrap(err, "验证码验证失败")
	}
	if loginToken == "" {
		return "", gerror.New("验证码验证失败")
	}

	// 更新 Token 信息
	m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
	_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
		LoginToken:          loginToken,
		LoginTokenExpiresAt: gtime.Now().Add(gtime.D * 30), // 30天后过期
		LastLoginAt:         gtime.Now(),
		Status:              int(consts.CamelOilTokenStatusAvailable), // 可用状态
	})

	if err != nil {
		return "", gerror.Wrap(err, "更新Token登录信息失败")
	}

	glog.Infof(ctx, "验证码验证成功，Token登录: tokenId=%d, phone=%s", req.TokenId, token.Phone)
	return loginToken, nil
}

// ResendVerificationCode 重新发送验证码
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, req *model.CamelOilTokenResendCodeInput) error {
	// 获取 Token 信息
	token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
	if err != nil {
		return gerror.Wrap(err, "查询Token信息失败")
	}

	if token == nil {
		return gerror.New("Token不存在")
	}

	// 检查 Token 状态，只有特定状态的 Token 才能重新发送验证码
	allowedStatuses := []int{
		int(consts.CamelOilTokenStatusPendingVerification), // 待验证码
		int(consts.CamelOilTokenStatusCodeSent),            // 验证码已发送
		int(consts.CamelOilTokenStatusVerificationFailed),  // 验证码验证失败
		int(consts.CamelOilTokenStatusLoginFailed),         // 登录失败
	}

	statusAllowed := false
	for _, status := range allowedStatuses {
		if token.Status == status {
			statusAllowed = true
			break
		}
	}

	if !statusAllowed {
		return gerror.New("Token状态不允许重新发送验证码")
	}

	client := camel_oil_api.NewClient(ctx)

	// 发送验证码
	_, err = client.SendCaptcha(ctx, token.Phone)
	if err != nil {
		// 更新状态为登录失败
		_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
			TokenId:   req.TokenId,
			NewStatus: consts.CamelOilTokenStatusLoginFailed,
			Remark:    "发送验证码失败",
		})
		return gerror.Wrap(err, "发送验证码失败")
	}

	// 更新 Token 状态为验证码已发送
	err = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
		TokenId:   req.TokenId,
		NewStatus: consts.CamelOilTokenStatusCodeSent,
		Remark:    "重新发送验证码成功",
	})
	if err != nil {
		return gerror.Wrap(err, "更新Token状态失败")
	}

	glog.Infof(ctx, "验证码重新发送成功: tokenId=%d, phone=%s", req.TokenId, token.Phone)
	return nil
}
