package player

import (
	"context"
	"log"
	"time"

	mhayaCrypto "github.com/mhaya/extend/crypto"
	cstring "github.com/mhaya/extend/string"
	mhayaTime "github.com/mhaya/extend/time"
	cutils "github.com/mhaya/extend/utils"
	"github.com/mhaya/game/game_cluster/internal/code"
	"github.com/mhaya/game/game_cluster/internal/constant"
	"github.com/mhaya/game/game_cluster/internal/data"
	"github.com/mhaya/game/game_cluster/internal/mdb"
	"github.com/mhaya/game/game_cluster/internal/mdb/models"
	"github.com/mhaya/game/game_cluster/internal/param"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func (p *actorPlayer) cashOut(req *param.CashOutReq) int32 {
	if !p.isOnline {
		return code.PlayerNotLogin
	}

	if p.Player.TonWall == "" {
		return code.TonWallNotExistsError
	}

	errCode := p.VerifyPwd(req.PassWord)
	if errCode > 0 {
		return errCode
	}

	num := int(cutils.Float64ByRatioToInt64(req.Amount, constant.MoneyRatio))
	var id int
	switch req.Tp {
	case 1:
		id = models.ItemU
	case 2:
		id = models.ItemTon
	}
	if p.Player.Item[id].Num >= num {
		old := p.Player.Item[id].Num
		p.Player.Item[id].Sub(num)
		rs, err := mdb.MDB.Collection(constant.CNameCashOutRecord).InsertOne(context.Background(), &models.CashOutRecord{
			UserName:    p.Player.UserName,
			NickName:    p.Player.NickName,
			OpenId:      p.Player.OpenId,
			Status:      0,
			Type:        1,
			AfterAmount: old,
			Amount:      num,
			Address:     p.Player.TonWall,
			CreateAt:    mhayaTime.Now().Unix(),
		})
		if err != nil || rs.InsertedID == "" {
			return code.Error
		}
		p.Player.IsCashOut = 1
		p.dirty = true
		p.cashOutStat(num)

		p.Player.SetPlayerRewardLog(models.SourceCashOut, 0, []data.ItemReward{}, []data.ItemReward{{4, models.ItemU, num}}, rs.InsertedID)
	} else {
		return code.NotEnoughItemsError
	}

	return code.OK
}

func (p *actorPlayer) setPwd(req *param.SetPwdReq) int32 {
	if !p.isOnline {
		return code.PlayerNotLogin
	}
	if len(p.Player.Password) > 0 {
		return code.PassWordIsExist
	}

	p.Player.Email = req.Mail
	p.Player.Salt = cstring.GetRandString(6)
	p.Player.Password = mhayaCrypto.MD5(req.PassWord + p.Player.Salt)
	p.dirty = true

	return code.OK
}

func (p *actorPlayer) VerifyPwd(pwd string) int32 {
	if p.isOnline {
		if p.Player.Password == mhayaCrypto.MD5(pwd+p.Player.Salt) {
			return code.OK
		}
		p.dirty = true
		p.Player.PwdErrTimes += 1
		if p.Player.PwdErrTimes > 3 {
			p.Player.PwdErrRefreshTime = mhayaTime.Now().Add(24 * time.Hour).Unix()
			return code.PassWordTooManyErrors
		}
	}
	return code.PassWordIsError
}

func (p *actorPlayer) cashOutList() ([]*models.ToUserWithdrawal, int32) {
	if !p.isOnline {
		return nil, code.PlayerNotLogin
	}

	findFilter := bson.M{"userName": p.Player.UserName}

	findOptions := options.Find().SetSort(bson.D{{"createAt", -1}}).SetLimit(int64(10))

	ctx := context.Background()
	cursor, err := mdb.MDB.Collection(constant.CNameCashOutRecord).Find(ctx, findFilter, findOptions)
	if err != nil {
		return nil, code.Error
	}
	defer func() {
		if closeErr := cursor.Close(ctx); closeErr != nil {
			log.Printf("Error closing cursor: %v", closeErr)
		}
	}()

	// 解析结果
	cashOutRecord := make([]*models.ToUserWithdrawal, 0)
	for cursor.Next(ctx) {
		var admin models.UserWithdrawal
		err = cursor.Decode(&admin)
		if err != nil {
			continue
		}
		cashOutRecord = append(cashOutRecord, admin.To())
	}

	return cashOutRecord, code.OK
}

func (p *actorPlayer) updCashOutStatus(tp int) {
	if !p.isOnline {
		return
	}
	if tp == 1 {
		if p.Player.IsCashOut == 0 {
			return
		}
	}

	findFilter := bson.M{"userName": p.Player.UserName, "state": 0}

	ctx := context.Background()
	cursor, err := mdb.MDB.Collection(constant.CNameCashOutRecord).Find(ctx, findFilter)
	if err != nil {
		return
	}

	defer func() {
		if closeErr := cursor.Close(ctx); closeErr != nil {
			log.Printf("Error closing cursor: %v", closeErr)
		}
	}()
	var num int
	for cursor.Next(ctx) {
		var cash models.UserWithdrawal
		err = cursor.Decode(&cash)
		if err != nil {
			continue
		}
		num++
		if cash.Status == 2 || (cash.Status == 1 && cash.Withdrawal == 1) {
			objID := primitive.ObjectID{}
			objID, _ = primitive.ObjectIDFromHex(cash.Id)
			updateCondition := bson.M{"_id": objID}
			_, err = mdb.MDB.Collection(constant.CNameCashOutRecord).UpdateOne(ctx, updateCondition, bson.M{"$set": bson.M{"state": 1, "updateAt": mhayaTime.Now().Unix()}})
			if err != nil {
				continue
			}
			switch cash.Type {
			case 1:
				if cash.Status == 1 {
					p.Player.Item[models.ItemU].RollbackAdd(cash.Amount, 1)
				} else {
					p.Player.Item[models.ItemU].RollbackAdd(cash.Amount, 0)
				}
			case 2:
				if cash.Status == 1 {
					p.Player.Item[models.ItemTon].RollbackAdd(cash.Amount, 1)
				} else {
					p.Player.Item[models.ItemTon].RollbackAdd(cash.Amount, 0)
				}
			}
			num--
		}
	}
	if num == 0 {
		p.Player.IsCashOut = 0
	}
	p.dirty = true
}

func (p *actorPlayer) updCashOutStatusByOld(tp int) {
	if !p.isOnline {
		return
	}
	/*	if tp == 1 {
		if p.Player.IsCashOut == 0 {
			return
		}
	}*/

	findFilter := bson.M{"userName": p.Player.UserName}

	ctx := context.Background()
	cursor, err := mdb.MDB.Collection(constant.CNameCashOutRecord).Find(ctx, findFilter)
	if err != nil {
		return
	}

	defer func() {
		if closeErr := cursor.Close(ctx); closeErr != nil {
			log.Printf("Error closing cursor: %v", closeErr)
		}
	}()
	var num int
	for cursor.Next(ctx) {
		var cash models.UserWithdrawal
		err = cursor.Decode(&cash)
		if err != nil {
			continue
		}
		if cash.Status == 0 {
			continue
		}
		if cash.State == 1 {
			continue
		}
		num++
		if cash.Status == 2 || (cash.Status == 1 && cash.Withdrawal == 1) {
			objID := primitive.ObjectID{}
			objID, _ = primitive.ObjectIDFromHex(cash.Id)
			updateCondition := bson.M{"_id": objID}
			_, err = mdb.MDB.Collection(constant.CNameCashOutRecord).UpdateOne(ctx, updateCondition, bson.M{"$set": bson.M{"state": 1, "updateAt": mhayaTime.Now().Unix()}})
			if err != nil {
				continue
			}
			switch cash.Type {
			case 1:
				if cash.Status == 1 {
					p.Player.Item[models.ItemU].RollbackAdd(cash.Amount, 1)
				} else {
					p.Player.Item[models.ItemU].RollbackAdd(cash.Amount, 0)
				}
			case 2:
				if cash.Status == 1 {
					p.Player.Item[models.ItemTon].RollbackAdd(cash.Amount, 1)
				} else {
					p.Player.Item[models.ItemTon].RollbackAdd(cash.Amount, 0)
				}
			}
			num--
		}
	}
	if num == 0 {
		p.Player.IsCashOut = 0
	}
	p.dirty = true
}
