package card_apple_account

import (
	"context"
	"github.com/duke-git/lancet/v2/slice"
	"github.com/gogf/gf/v2/os/gmlock"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"kami/utility/cache"
	"slices"

	"kami/internal/consts"
	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"
	"kami/utility/utils"

	"github.com/shopspring/decimal"
)

// GetAccordingAccount 账户分配算法，适合多线程
func (a *sAppleAccount) GetAccordingAccount(ctx context.Context, amount decimal.Decimal, excludeAccountIds []string) (accountInfo *entity.V1CardAppleAccountInfo, err error) {
	gmlock.Lock("sAppleAccount_GetAccordingAccount")
	defer gmlock.Unlock("sAppleAccount_GetAccordingAccount")

	//获取所有的可用用户
	users, err := service.SysUser().GetUsersAll(ctx)
	if err != nil {
		return
	}
	// 把管理员临时添加进来
	users = append(users, &model.SysUserSimpleOutput{Id: ""})

	// 检索当前用户在所有用户的位置
	currentAccountInfo, err := a.GetCurrentTargetAccount(ctx)
	if err != nil {
		return
	}

	currentUserIndex := slices.IndexFunc(users, func(item *model.SysUserSimpleOutput) bool {
		return item.Id == currentAccountInfo.UserId
	})
	//如果没有当前账户，则从第一个用户开始
	if currentUserIndex == -1 {
		currentUserIndex = 0
	}

	isEnough := false
	excludeAccountList := a.getAllCheckedAccountByFirstAccount(ctx)

	for i := 0; i < len(users)+1; i++ {
		isEnough = false
		// 从当前用户开始，循环遍历所有用户
		currentUser := users[(currentUserIndex+i)%len(users)]
		m := dao.V1CardAppleAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()).
			Where(dao.V1CardAppleAccountInfo.Columns().CreatedUserId, currentUser.Id).
			Where(dao.V1CardAppleAccountInfo.Columns().Status, consts.AppleAccountNormal).
			OrderAsc(dao.V1CardAppleAccountInfo.Columns().CreatedAt)

		if len(excludeAccountIds) > 0 {
			m = m.WhereNotIn(dao.V1CardAppleAccountInfo.Columns().Id, excludeAccountIds)
		}
		if len(excludeAccountList) > 0 {
			m = m.WhereNotIn(dao.V1CardAppleAccountInfo.Columns().Account, excludeAccountList)
		}

		// 查找当前用户的所有订单
		err = m.Scan(&accountInfo)
		err = utils.HandleNoRowsError(err)
		// 管理员
		if accountInfo != nil && accountInfo.Id != "" {
			// 当前用户是正在使用账户，但当前账户不是正在使用的情况，并且不是循环完一圈的情况
			if accountInfo.CreatedUserId == currentAccountInfo.UserId &&
				accountInfo.Id != currentAccountInfo.AccountId &&
				i != len(users) {
				continue
			}
			if currentUser.Id == "" {
				isEnough = true
				break
			}

			if isNormal, err2 := service.SysUser().CheckUserNormal(ctx, accountInfo.CreatedUserId); err2 != nil || !isNormal {
				continue
			}

			isEnough, _ = service.SysUserPayment().CheckBalanceEnough(ctx, &model.SysUserPaymentCheckBalanceInput{
				UserId: accountInfo.CreatedUserId,
				Amount: amount,
			})
			if isEnough {
				break
			}
		}
	}

	if !isEnough {
		_ = a.ClearCurrentTargetAccount(ctx)
		return
	}

	// 如果切换账号或者切换id后，需要重新切换账户
	if accountInfo != nil {
		if accountInfo.CreatedUserId != currentAccountInfo.UserId ||
			accountInfo.Id != currentAccountInfo.AccountId {
			err = a.SetCurrentTargetAccount(ctx, &model.AccountIdInfo{
				UserId:    accountInfo.CreatedUserId,
				AccountId: accountInfo.Id,
			})
		}
		//账户过期时间
		_ = cache.NewCache().Set(ctx, cache.PrefixRedeemAppleAccountLimitedType.Key(accountInfo.Account+":"+utils.GenerateRandomUUID()), 1, gtime.M)
	}
	return
}

func (a *sAppleAccount) getAllCheckedAccountByFirstAccount(ctx context.Context) []string {
	targetKeys := a.getAllCheckedAccountByFirstAccountUnUnique(ctx)
	targetKeys = slice.Unique(slice.Filter(targetKeys, func(index int, item string) bool {
		return slice.Count(targetKeys, item) >= 6
	}))
	return targetKeys
}

func (a *sAppleAccount) getAllCheckedAccountByFirstAccountUnUnique(ctx context.Context) []string {
	keys, err := cache.NewCache().KeyStrings(ctx)
	if err != nil {
		return make([]string, 0)
	}
	targetKeys := slice.Filter(keys, func(index int, item string) bool {
		tmpKeyList := gstr.Split(item, ":")
		if len(tmpKeyList) == 3 && tmpKeyList[0] == gconv.String(cache.PrefixRedeemAppleAccountLimitedType) {
			return true
		}
		return false
	})
	targetKeys = slice.Map(targetKeys, func(index int, item string) string {
		return gstr.Split(item, ":")[1]
	})
	return targetKeys
}
