package service

import (
	"context"
	"errors"
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"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/nodes/webadmin/entity"
	"github.com/mhaya/game/game_cluster/nodes/webadmin/model"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"golang.org/x/crypto/bcrypt"
)

type Admin struct {
	db *mongo.Database
}

func NewAdmin() *Admin {
	return &Admin{
		db: mdb.MDB,
	}
}

func (a *Admin) GetDB() *mongo.Database {
	return a.db
}

func (a *Admin) GetDBName() string {
	return "admin"
}
func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// HashPassword 加密密码
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes), err
}

// Login 登录
func (a *Admin) Login(ctx *gin.Context, username string, password string) (*entity.AdminResp, error) {
	user, err := a.QueryUserByUsername(ctx, username)
	if err != nil {
		log.Printf("Failed to query user: %s", err)
		return nil, fmt.Errorf("failed to query user: %s", err)
	}
	// 判断用户状态
	if user.Status != 1 {
		log.Println("User is disabled")
		return nil, errors.New("user is disabled")
	}
	// 判断密码
	if !CheckPasswordHash(password, user.Password) {
		log.Println("Invalid username or password")
		return nil, errors.New("invalid username or password")
	}
	// 创建token
	generateToken, err := user.GenerateToken()
	if err != nil {
		return nil, err
	}
	// 保存token 到 redis 中 过期时间为1天
	err = mdb.RDB.Set(ctx, generateToken, user.Username, 24*time.Hour).Err()
	if err != nil {
		return nil, err
	}
	err = a.loginAuthSetRoleRedis(user.RoleId, generateToken)
	if err != nil {
		return nil, err
	}
	// 更新用户登录时间
	_, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_time": time.Now().Unix()}})
	log.Printf("Login successful for user: %s", username)
	if err != nil {
		return nil, err
	}
	// 更新用户IP
	ip := ctx.ClientIP()
	_, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_ip": ip}})

	// 返回用户信息
	log.Printf("Returning user: %s", username)
	return &entity.AdminResp{
		ToKen:  generateToken,
		RoleID: user.RoleId,
	}, nil
}

// LoginAuthSetRoleRedis 登录时写入该用户的权限
func (a *Admin) loginAuthSetRoleRedis(roleID, generateToken string) error {
	if roleID == constant.AdminAccess {
		mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, constant.AdminAccess, 1)
		mdb.RDB.Expire(context.Background(), "admin::token::"+generateToken, 24*time.Hour).Err()

		return nil
	}

	// 写入redis
	role := models.Roles{}
	collection := mdb.MDB.Collection(role.TableName())
	roleIdObj, _ := primitive.ObjectIDFromHex(roleID)
	filter := bson.M{"_id": roleIdObj, "status": 1}
	err := collection.FindOne(context.TODO(), filter).Decode(&role)
	if err != nil {
		return err
	}
	roleAccess := models.RoleAccess{}
	collection = mdb.MDB.Collection(roleAccess.TableName())
	roleAccessFilter := bson.M{"role_id": roleID}
	err = collection.FindOne(context.TODO(), roleAccessFilter).Decode(&roleAccess)
	if err != nil {
		return err
	}
	// 写入redis
	var accessIDS []primitive.ObjectID
	for _, v := range roleAccess.AccessID {
		accessIdObj, _ := primitive.ObjectIDFromHex(v)
		accessIDS = append(accessIDS, accessIdObj)
	}

	access := models.Access{}
	var accessList []models.Access
	collection = mdb.MDB.Collection(access.TableName())
	accessFilter := bson.M{"_id": bson.M{"$in": accessIDS}}
	cursor, err := collection.Find(context.Background(), accessFilter)
	if err != nil {
		return err
	}
	if err = cursor.All(context.Background(), &accessList); err != nil {
		return err
	}
	for _, v := range accessList {
		mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, v.URL, 1)
	}
	mdb.RDB.Expire(context.Background(), "admin::token::"+generateToken, 24*time.Hour).Err()
	return nil

}

// QueryUserByUsername 根据用户名查询用户
func (a *Admin) QueryUserByUsername(ctx context.Context, username string) (*model.Admin, error) {
	admin := &model.Admin{}
	err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin)
	if errors.Is(err, mongo.ErrNoDocuments) && username == "admin" {
		// 如果是admin 登录的话 创建一个初始的admin并且存入数据库
		pwd, err := HashPassword("123456")
		if err != nil {
			return nil, err
		}
		admin = &model.Admin{
			Username:      constant.AdminAccess,
			Password:      pwd,
			RealName:      constant.AdminAccess,
			Pid:           "0",
			RoleId:        constant.AdminAccess,
			ManagerAuth:   0,
			Status:        1,
			CreatedAt:     0,
			UpdatedAt:     0,
			DeletedAt:     0,
			LastLoginIp:   "",
			LastLoginTime: 0,
		}
		_, err = mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, bson.M{
			"username":  constant.AdminAccess,
			"password":  pwd,
			"real_name": constant.AdminAccess,
			"pid":       "0",
			"role_id":   constant.AdminAccess,
			"status":    1,
		})
		if err != nil {
			return nil, err
		}
		return admin, nil
	}
	if err != nil {
		return nil, err
	}

	return admin, nil

}

// ChangePassword 修改管理员密码
func (a *Admin) ChangePassword(ctx context.Context, username string, password string) error {
	// 更新密码
	password, _ = HashPassword(password)
	_, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"password": password}})
	if err != nil {
		return err
	}
	return nil
}

// Add 添加管理员
func (a *Admin) Add(ctx context.Context, username string, password string, realName string, pid string, roleId string, status int) error {
	// 判断账号是否重复
	admin := model.Admin{}
	err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin)
	if errors.Is(err, mongo.ErrNoDocuments) {
		password, _ = HashPassword(password)
		_, err := mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, bson.M{
			"username":   username,
			"password":   password,
			"real_name":  realName,
			"pid":        pid,
			"role_id":    roleId,
			"status":     status,
			"created_at": time.Now().Unix(),
			"updated_at": time.Now().Unix(),
		})
		if err != nil {
			return err
		}
		return nil
	}
	return fmt.Errorf("账号已存在")
}

// Delete 删除管理员
func (a *Admin) Delete(ctx context.Context, username string) error {
	_, err := mdb.MDB.Collection(a.GetDBName()).DeleteOne(ctx, bson.M{"username": username})
	if err != nil {
		return err
	}
	return nil
}

// UpdateStatus updateStatus
func (a *Admin) UpdateStatus(ctx context.Context, username string, status int) error {
	_, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"status": status}})
	if err != nil {
		return err
	}
	return nil

}

// FindAll 查找所有管理员信息
func (a *Admin) FindAll(ctx context.Context, page int, pageSize int, username string) ([]*entity.AdminListResp, int64, error) {
	// 日志记录
	log.Printf("Finding admins with page %d and page size %d, username: %s", page, pageSize, maskUsername(username))

	// 验证参数
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}

	// 构建查询条件
	filter := bson.M{}
	if username != "" {
		filter["username"] = bson.M{"$regex": escapeRegex(username), "$options": "i"}
	}
	// 查询总数
	count, err := mdb.MDB.Collection("admin").CountDocuments(ctx, filter)
	if err != nil {
		return nil, 0, err
	}

	// 设置分页选项
	skip := (page - 1) * pageSize
	limit := pageSize
	findOptions := options.Find().SetSkip(int64(skip)).SetLimit(int64(limit))

	// 执行查询
	cursor, err := mdb.MDB.Collection("admin").Find(ctx, filter, findOptions)
	if err != nil {
		return nil, 0, err
	}
	defer func() {
		if closeErr := cursor.Close(ctx); closeErr != nil {
			log.Printf("Error closing cursor: %v", closeErr)
		}
	}()

	// 解析结果
	admins := make([]*model.Admin, 0)
	for cursor.Next(ctx) {
		var admin model.Admin
		err := cursor.Decode(&admin)
		if err != nil {
			return nil, 0, err
		}
		admins = append(admins, &admin)
	}

	if err := cursor.Err(); err != nil {
		return nil, 0, err
	}

	var data []*entity.AdminListResp
	for _, admin := range admins {
		roleName := ""
		roleName, _ = a.GetRoleName(admin.RoleId)

		data = append(data, &entity.AdminListResp{
			Id:            admin.GetID(),
			Username:      admin.Username,
			RealName:      admin.RealName,
			RoleId:        admin.RoleId,
			RoleName:      roleName,
			Status:        admin.Status,
			CreatedAt:     admin.CreatedAt,
			UpdatedAt:     admin.UpdatedAt,
			LastLoginIp:   admin.LastLoginIp,
			LastLoginTime: admin.LastLoginTime,
		})
	}

	return data, count, nil
}

func (a *Admin) GetRoleName(roleID string) (string, error) {
	objID, err := primitive.ObjectIDFromHex(roleID)
	if err != nil {
		return "", err
	}
	var role models.Roles
	err = mdb.MDB.Collection(role.TableName()).FindOne(context.Background(), bson.M{"_id": objID}).Decode(&role)
	return role.Name, err
}

// GetServerStatus 获取服务器状态
func (a *Admin) GetServerStatus(ctx context.Context) ([]*models.PlayerServerLoadStat, error) {
	// 执行查询
	cursor, err := mdb.MDB.Collection(constant.CNameServerLoadStat).Find(ctx, bson.M{})
	if err != nil {
		return nil, err
	}
	defer func() {
		if closeErr := cursor.Close(ctx); closeErr != nil {
			log.Printf("Error closing cursor: %v", closeErr)
		}
	}()
	// 解析结果
	admins := make([]*models.PlayerServerLoadStat, 0)
	for cursor.Next(ctx) {
		var admin models.PlayerServerLoadStat
		err := cursor.Decode(&admin)
		if err != nil {
			return nil, err
		}
		admins = append(admins, &admin)
	}

	if err := cursor.Err(); err != nil {
		return nil, err
	}
	return admins, nil
}

// 辅助函数：对 username 进行脱敏处理
func maskUsername(username string) string {
	if username == "" {
		return ""
	}
	return strings.Repeat("*", len(username))
}

// 辅助函数：对正则表达式进行转义
func escapeRegex(s string) string {
	return regexp.QuoteMeta(s)
}
