package module

import (
	"context"
	"fmt"
	jsoniter "github.com/json-iterator/go"
	"github.com/mhaya/game/game_cluster/internal/constant"
	"github.com/mhaya/game/game_cluster/internal/mdb"
	"github.com/mhaya/game/game_cluster/internal/mdb/models"
	"github.com/mhaya/game/game_cluster/internal/token"
	clog "github.com/mhaya/logger"
	"github.com/mhaya/net/parser/simple"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"time"
)

type (
	ActorSaves struct {
		simple.ActorBase
	}
)

func (p *ActorSaves) AliasID() string {
	return "save_dbs"
}

func (p *ActorSaves) OnInit() {
	p.Timer().Add(50*time.Second, p.saveAccountDB1)
	p.Timer().Add(60*time.Second, p.savePlayerDB1)
}

func (p *ActorSaves) saveAccountDB1() {
	go p.saveAccountDB()
}

func (p *ActorSaves) savePlayerDB1() {
	go p.savePlayerDBTwo()
}

func (p *ActorSaves) saveAccountDB() {
	clog.Debugf("saveAccountDb ==> start()")
	key := 0
	newKey := 0
	bulkUpdOps := []mongo.WriteModel{}
	bulkInsAccountOps := []mongo.WriteModel{}
	bulkInsPlayerOps := []mongo.WriteModel{}
	updAccount := []string{}
	insAccount := []string{}
	insPlayer := []string{}
	ctx := context.Background()
	newAccounts := mdb.RDB.HGetAll(ctx, constant.NewAccounts).Val()
	for k, v := range newAccounts {
		var account models.Account
		if v == "1" {
			if newKey < 5000 {
				acc, _ := mdb.RDB.Get(ctx, fmt.Sprintf("%v:%v", constant.CNameAccount, k)).Bytes()
				if len(acc) > 0 {
					err := jsoniter.Unmarshal(acc, &account)
					if err != nil {
						continue
					}
				}
				if account.OpenId != "" {
					bulkInsAccountOps = append(bulkInsAccountOps, mongo.NewInsertOneModel().SetDocument(&account))
					player := models.NewPlayer(token.New(2, account.OpenId, account.UserName, "", "", ""))
					bulkInsPlayerOps = append(bulkInsPlayerOps, mongo.NewInsertOneModel().SetDocument(&player))
					insAccount = append(insAccount, account.OpenId)
					insPlayer = append(insPlayer, account.OpenId)
				}
			}
			newKey++
		} else {
			if key < 5000 {
				acc, _ := mdb.RDB.Get(ctx, fmt.Sprintf("%v:%v", constant.CNameAccount, k)).Bytes()
				if len(acc) > 0 {
					err := jsoniter.Unmarshal(acc, &account)
					if err != nil {
						continue
					}
				}
				filter := bson.M{"openId": account.OpenId}
				update := bson.M{"$set": &account}
				bulkUpdOps = append(bulkUpdOps, mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update))
				updAccount = append(updAccount, account.OpenId)
				key++
			}
		}
		if newKey > 5000 || key > 5000 {
			break
		}
	}
	if len(bulkUpdOps) > 0 {
		_, err := mdb.MDB.Collection(constant.CNameAccount).BulkWrite(context.Background(), bulkUpdOps)
		if err != nil {
			clog.Fatalf("saveAccountDB Bulk write failed: %v", err)
		}
		mdb.RDB.HDel(ctx, constant.NewAccounts, updAccount...)
		clog.Infof("update account to db count=%v", len(bulkUpdOps))
	}

	if len(bulkInsAccountOps) > 0 {
		_, err := mdb.MDB.Collection(constant.CNameAccount).BulkWrite(context.Background(), bulkInsAccountOps)
		if err != nil {
			clog.Errorf("Bulk write failed: %v", err)
		}
		mdb.RDB.HDel(ctx, constant.NewAccounts, insAccount...)
		clog.Infof("insert account to db count=%v", len(bulkInsAccountOps))
	}
	if len(bulkInsPlayerOps) > 0 {
		_, err := mdb.MDB.Collection(constant.CNamePlayer).BulkWrite(context.Background(), bulkInsPlayerOps)
		if err != nil {
			clog.Errorf("Bulk write failed: %v", err)
		}
		mdb.RDB.HDel(ctx, constant.NewPlayers, insPlayer...)
		clog.Infof("insert player info to db count=%v", len(bulkInsPlayerOps))
	}

	clog.Debugf("saveAccountDb ==> end()")
}

func (p *ActorSaves) savePlayerDB() {
	clog.Debugf("saveAccountDb ==> start()")
	key := 0
	bulkUpdOps := []mongo.WriteModel{}
	ctx := context.Background()
	newPlayers := mdb.RDB.HGetAll(ctx, constant.NewPlayers).Val()
	updPlayer := []string{}
	for k, _ := range newPlayers {
		if key < 5000 {
			var player models.Player
			acc, _ := mdb.RDB.Get(ctx, fmt.Sprintf("%v:%v", constant.CNamePlayer, k)).Bytes()
			if len(acc) > 0 {
				err := jsoniter.Unmarshal(acc, &player)
				if err != nil {
					continue
				}
			}
			filter := bson.M{"openId": player.OpenId}
			update := bson.M{"$set": &player}
			bulkUpdOps = append(bulkUpdOps, mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update))
			updPlayer = append(updPlayer, player.OpenId)
		}
		key++
		if key > 5000 {
			break
		}
	}

	if len(bulkUpdOps) > 0 {
		_, err := mdb.MDB.Collection(constant.CNamePlayer).BulkWrite(context.Background(), bulkUpdOps)
		if err != nil {
			clog.Fatalf("saveAccountDB Bulk write failed: %v", err)
		}
		mdb.RDB.HDel(ctx, constant.NewPlayers, updPlayer...)
		clog.Infof("update player info to db count=%v", len(bulkUpdOps))
	}
	clog.Debugf("saveAccountDb ==> end()")

}

func (p *ActorSaves) savePlayerDBTwo() {
	clog.Debugf("savePlayerDBTwo ==> start()")
	key := 0
	bulkUpdOps := []mongo.WriteModel{}
	ctx := context.Background() // 可以考虑传入 ctx，提升代码的灵活性
	newPlayers := mdb.RDB.HGetAll(ctx, constant.NewPlayers).Val()
	updPlayer := []string{}

	// 使用 goroutines 并发处理玩家更新
	for k, _ := range newPlayers {
		if key >= 5000 {
			break // 优化了循环条件，提前退出
		}

		var player models.Player
		acc, err := mdb.RDB.Get(ctx, fmt.Sprintf("%v:%v", constant.CNamePlayer, k)).Bytes()
		if err != nil {
			// 记录 Redis 错误并继续
			clog.Errorf("Failed to get player %v from Redis: %v", k, err)
			continue
		}

		if len(acc) > 0 {
			err = jsoniter.Unmarshal(acc, &player)
			if err != nil {
				clog.Errorf("Failed to unmarshal player %v: %v", k, err)
				continue
			}
		}

		// 构建 MongoDB 更新操作
		filter := bson.M{"openId": player.OpenId}
		update := bson.M{"$set": player} // 这里可以直接使用 player，而不需要取地址

		// 添加到 Bulk 操作队列
		bulkUpdOps = append(bulkUpdOps, mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update))
		updPlayer = append(updPlayer, player.OpenId)

		key++
	}

	// 执行批量更新
	if len(bulkUpdOps) > 0 {
		_, err := mdb.MDB.Collection(constant.CNamePlayer).BulkWrite(ctx, bulkUpdOps)
		if err != nil {
			clog.Errorf("Bulk write to MongoDB failed: %v", err)
			return // 如果 bulk 更新失败，停止执行后续操作
		}

		// 删除 Redis 中的玩家数据
		_, err = mdb.RDB.HDel(ctx, constant.NewPlayers, updPlayer...).Result()
		if err != nil {
			clog.Errorf("Failed to delete players from Redis: %v", err)
		}

		clog.Infof("Updated player info to MongoDB, count=%v", len(bulkUpdOps))
	}
	clog.Debugf("savePlayerDBTwo ==> start()")

}

/*func (p *ActorSaves) OnFindChild(msg *cfacade.Message) (cfacade.IActor, bool) {
	// 动态创建 player child actor
	childID := msg.TargetPath().ChildID
	childActor, err := p.Child().Create(childID, &{
		isOnline: false,
	})

	if err != nil {
		return nil, false
	}

	return childActor, true
}*/

func (p *ActorSaves) OnStop() {
	clog.Infof("ActorSaves stop")
}
