package card_redeem_account

import (
	"context"
	"kami/internal/consts"
	"kami/internal/model"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/cache"

	"github.com/duke-git/lancet/v2/pointer"
	"github.com/duke-git/lancet/v2/slice"
	"github.com/gogf/gf/v2/database/gdb"
)

// GetNextOneSortByAccount 轮换策略，按照充值账户来轮换
func (a *sCardRedeemAccount) getNextOneSortByAccount(ctx context.Context, category consts.CardRedeemAccountCategory, chargeAmount float64, tx gdb.TX) (output *entity.V1CardRedeemAccountInfo, err error) {
	type storeInfo struct {
		AccountId string
		//	轮询账户的次数
		AccountIndex int
		UserId       string
		UserIndex    int
	}
	targetAccountIdCache, _ := cache.NewCache().Get(ctx, cache.RedeemAccountTargetIDByCKAndUser.Key(category))

	currentStoreInfo := storeInfo{}
	if !pointer.IsNil(targetAccountIdCache) && !targetAccountIdCache.IsNil() {
		_ = targetAccountIdCache.Scan(&currentStoreInfo)
	}

	//获取所有的账号
	accountList, err := a.GetAllAvailableAccount(ctx, category, chargeAmount, tx)
	if err != nil {
		return
	}
	//获取所有的用户
	userList, _ := service.SysUser().GetAllNormalWithPaymentAndChannelCfg(ctx, chargeAmount, tx)

	//获取当前用户的索引
	currentUser, ok := slice.FindBy(userList, func(index int, item *model.UserSearchWithPaymentAndCfgOutput) bool {
		return item.Id == currentStoreInfo.UserId
	})

	currentUserIndex := currentStoreInfo.UserIndex % len(userList)
	if ok {
		// 如果当前轮询用户存在，获取当前用户的索引
		currentUserIndex = slice.IndexOf(userList, currentUser)
	} else {
		//如果当前轮询用户不存在，重置轮询账户
		currentStoreInfo.AccountIndex = -1
	}

	//判断当前的账户是否存在
	isTargetAccountExist := false
	for i := -1; i < len(userList); i++ {
		targetUser := userList[currentUserIndex%len(userList)]
		currentAccountList := slice.Filter(accountList, func(index int, item *entity.V1CardRedeemAccountInfo) bool {
			return item.CreateUserId == targetUser.Id
		})
		// 获取指定账户配置
		currentCfg, ok2 := slice.FindBy(targetUser.ChannelCfg, func(index int, item model.SysUserChannelCfg) bool {
			return item.Name == category.String()
		})
		currentCfgNum := consts.DefaultExchangeConcurrentNum
		if ok2 {
			currentCfgNum = currentCfg.Num
		}
		//取当前用户下指定次数的账户
		if len(currentAccountList) > currentCfgNum {
			currentAccountList = currentAccountList[:currentCfgNum]
		}
		//取当前账户的下一个账户
		if currentStoreInfo.AccountIndex+1 < len(currentAccountList) {
			nextAccount := currentAccountList[(currentStoreInfo.AccountIndex+1)%len(currentAccountList)]
			if service.Rate().Allow(ctx, model.LimiterTypeCardInfoRedeemAccountCookieSet, nextAccount.Id) {
				currentStoreInfo = storeInfo{
					UserId:       userList[currentUserIndex%len(userList)].Id,
					UserIndex:    currentUserIndex % len(userList),
					AccountIndex: (currentStoreInfo.AccountIndex + 1) % len(currentAccountList),
					AccountId:    nextAccount.Id,
				}
				output = nextAccount
				isTargetAccountExist = true
				break
			}
		}
		currentUserIndex++
		currentStoreInfo = storeInfo{
			UserId:       userList[currentUserIndex%len(userList)].Id,
			UserIndex:    currentUserIndex % len(userList),
			AccountIndex: -1,
		}
	}
	if isTargetAccountExist {
		_ = cache.NewCache().Set(ctx, cache.RedeemAccountTargetIDByCKAndUser.Key(category), currentStoreInfo, 0)
	} else {
		_ = cache.NewCache().Set(ctx, cache.RedeemAccountTargetIDByCKAndUser.Key(category), storeInfo{}, 0)
	}
	return
}

func (a *sCardRedeemAccount) getRandomAccount(ctx context.Context, category consts.CardRedeemAccountCategory, chargeAmount float64, tx gdb.TX) (output *entity.V1CardRedeemAccountInfo, err error) {
	//获取所有的账号
	accountList, err := a.GetAllAvailableAccount(ctx, category, chargeAmount, tx)
	if err != nil {
		return
	}
	//获取所有的用户
	userList, _ := service.SysUser().GetAllNormalWithPaymentAndChannelCfg(ctx, chargeAmount, tx)
	accountList = slice.Filter(accountList, func(index int, item *entity.V1CardRedeemAccountInfo) bool {
		return slice.ContainBy(userList, func(item2 *model.UserSearchWithPaymentAndCfgOutput) bool {
			return item.CreateUserId == item2.Id
		})
	})
	output, _ = slice.Random(accountList)
	return
}

func (a *sCardRedeemAccount) GetAvailableAccount(ctx context.Context, category consts.CardRedeemAccountCategory, chargeAmount float64, tx gdb.TX) (output *entity.V1CardRedeemAccountInfo, err error) {
	strategy, _ := service.SysConfigDict().GetRedeemScheduleStrategy(ctx, category, tx)
	switch strategy {
	case consts.RedeemCardScheduleStrategyTypeRandom:
		return a.getRandomAccount(ctx, category, chargeAmount, tx)
	default:
		return a.getNextOneSortByAccount(ctx, category, chargeAmount, tx)
	}
}
