package service

import (
	"context"
	"math"
	"time"

	mhayaTime "github.com/mhaya/extend/time"
	"github.com/mhaya/game/game_cluster/internal/code"
	"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/adminapi/common"
	"github.com/mhaya/game/game_cluster/nodes/adminapi/entity"
	"github.com/mhaya/game/game_cluster/nodes/adminapi/model"
	mhayaLogger "github.com/mhaya/logger"
	"github.com/spf13/cast"
	"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"
)

type Synthesis struct {
	db *mongo.Database
}

func NewSynthesis() *Synthesis {
	return &Synthesis{
		db: mdb.MDB,
	}
}

func (s *Synthesis) FindMDBUserLogDaily(req entity.UserLogDailyReq) (*entity.UserLogDailyResp, *code.Result) {
	// 定义上下文
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()

	// 指定集合
	collection := mdb.MDB.Collection(constant.CNamePlayerDailyRecord)

	// 构建查询条件 - 如果查询值为空那就不添加查询条件
	filter := bson.M{}

	if req.StartTime != 0 {
		filter["daily"] = bson.M{
			"$gte": req.StartTime,
			"$lte": req.EndTime,
		}
	}

	if req.Platform != "" && req.Platform != "all" {
		filter["platform"] = req.Platform
	}

	if req.Channel != "" {
		filter["channel"] = req.Channel
	}

	// 分页参数
	skip := (req.Page - 1) * req.Size
	// 计算总数
	count, err := collection.CountDocuments(ctx, filter)
	if err != nil {
		mhayaLogger.Warnf("FindMDBUserLogDaily CountDocuments error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	// 执行查询
	opts := options.Find()
	opts.SetSkip(int64(skip))
	opts.SetLimit(int64(req.Size))
	opts.SetSort(bson.D{{"daily", -1}})

	cursor, err := collection.Find(ctx, filter, opts)
	if err != nil {
		mhayaLogger.Warnf("FindMDBUserLogDaily Find error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}
	defer cursor.Close(ctx)

	// 解析查询结果
	var results []*entity.UserLogDailyDetail

	for cursor.Next(ctx) {
		var result *entity.UserLogDailyDetail
		err := cursor.Decode(&result)
		if err != nil {
			mhayaLogger.Warnf("FindMDBUserLogDaily Decode error:%v", err)
			return nil, common.NewResult(code.InternalError)
		}
		results = append(results, result)
	}
	// 同一天的数据全部放到platform= ALl 且数据累加
	// 如果没有platform=all 的那就新增一个 同一个时间段只能有一个 platform=all
	// 将同一天的数据累加到platform=all的记录中
	allPlatformRecordMap := make(map[int64]*entity.UserLogDailyDetail)

	for _, result := range results {
		allPlatformRecordMap[result.Timestamp] = &entity.UserLogDailyDetail{
			Timestamp: result.Timestamp,
			Platform:  "all",
		}
	}
	for _, v := range results {
		if v.Timestamp == allPlatformRecordMap[v.Timestamp].Timestamp {
			allPlatformRecordMap[v.Timestamp].Registered += v.Registered
			allPlatformRecordMap[v.Timestamp].LoggedIn += v.LoggedIn
			allPlatformRecordMap[v.Timestamp].NewActive += v.NewActive
			allPlatformRecordMap[v.Timestamp].OldActive += v.OldActive
			allPlatformRecordMap[v.Timestamp].TotalPoints += v.TotalPoints
			allPlatformRecordMap[v.Timestamp].UProduced += v.UProduced
			allPlatformRecordMap[v.Timestamp].UCashout += v.UCashout
			allPlatformRecordMap[v.Timestamp].NewLogin += v.NewLogin
			allPlatformRecordMap[v.Timestamp].OldLogin += v.OldLogin
		}
	}

	// 替换原有结果
	for _, record := range allPlatformRecordMap {
		results = append(results, record)
	}

	return &entity.UserLogDailyResp{
		Details: results,
		Total:   count,
	}, nil
}

// FindWithdrawal 根据请求查询提现记录
func (s *Synthesis) FindWithdrawal(req entity.UserWithdrawalReq) (*entity.UserWithdrawalResp, *code.Result) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()
	collection := mdb.MDB.Collection(constant.CNameCashOutRecord)

	// 构建过滤器
	filter := bson.M{}
	if req.UserName != "" {
		filter["userName"] = req.UserName
	}
	if req.NickName != "" {
		filter["nickName"] = req.NickName
	}
	if req.ID != "" {
		filter["_id"], _ = primitive.ObjectIDFromHex(req.ID)
	}

	if req.StartTime != 0 {
		filter["createAt"] = bson.M{
			"$gte": req.StartTime,
			"$lte": req.EndTime,
		}
	}

	// 设置分页选项
	findOptions := options.Find()
	findOptions.SetSkip(int64((req.Page - 1) * req.Size))
	findOptions.SetLimit(int64(req.Size))
	findOptions.SetSort(bson.D{{"createAt", -1}})

	// 获取总数total
	count, err := collection.CountDocuments(ctx, filter)
	if err != nil {
		mhayaLogger.Warnf("FindWithdrawal CountDocuments error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	// 查询数据
	var results []*entity.UserWithdrawalDetail
	cursor, err := collection.Find(ctx, filter, findOptions)
	if err != nil {
		mhayaLogger.Warnf("FindWithdrawal Find error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	defer cursor.Close(ctx)
	// 解析结果
	for cursor.Next(ctx) {
		var result entity.UserWithdrawalDetail
		if err := cursor.Decode(&result); err != nil {
			mhayaLogger.Warnf("FindWithdrawal Decode error:%v", err)
			return nil, common.NewResult(code.InternalError)
		}
		results = append(results, &result)
	}

	if err := cursor.Err(); err != nil {
		mhayaLogger.Warnf("FindWithdrawal cursor error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	return &entity.UserWithdrawalResp{
		Details: results,
		Total:   count,
	}, nil
}

// WithdrawalStatus 更新提现状态
func (s *Synthesis) WithdrawalStatus(req entity.UserWithdrawalStatus) *code.Result {
	// ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	// defer cancel()
	collection := mdb.MDB.Collection(constant.CNameCashOutRecord)

	// 更新条件
	updateCondition := bson.M{"userName": req.UserName}
	// 更新内容
	updateContent := bson.M{"$set": bson.M{"status": req.Status}}
	// 设置更新选项
	updateOptions := options.Update() // 设置 upsert 选项
	// 执行更新操作
	_, err := collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
	if err != nil {
		mhayaLogger.Warnf("WithdrawalStatus UpdateOne error:%v", err)
		return common.NewResult(code.InternalError)
	}

	return nil
}

// WithdrawalStatusBatch 更新提现状态
func (s *Synthesis) WithdrawalStatusBatch(req entity.UserWithdrawalStatusBatch) *code.Result {
	collection := mdb.MDB.Collection(constant.CNameCashOutRecord)
	if len(req.ID) == 0 {
		return common.NewResult(code.ParamError)
	}

	for _, id := range req.ID {
		objID := primitive.ObjectID{}
		objID, _ = primitive.ObjectIDFromHex(id)
		updateCondition := bson.M{"_id": objID}
		updateContent := bson.M{}
		withdrawal := models.CashOutRecord{}
		err := collection.FindOne(context.TODO(), updateCondition).Decode(&withdrawal)
		if err != nil {
			mhayaLogger.Warnf("WithdrawalStatusBatch FindOne error:%v", err)
			continue
		}

		if req.Withdrawal != 0 {
			if withdrawal.Status == 1 {
				updateContent = bson.M{"$set": bson.M{"withdrawal": req.Withdrawal}}
			} else {
				continue
			}
		}

		if req.Status > 0 {
			if withdrawal.Status != 0 {
				continue
			}
			updateContent = bson.M{"$set": bson.M{"status": req.Status}}
		}

		updateOptions := options.Update().SetUpsert(true)
		_, err = collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
		if err != nil {
			mhayaLogger.Warnf("WithdrawalStatusBatch UpdateOne error:%v", err)
			continue
		}
	}

	return nil
}

// FindUserCountryCount 查询用户国家分布
//
// 返回值为 UserCountryResp 的切片和错误。
func (s *Synthesis) FindUserCountryCount() (*entity.UserCountryResp, *code.Result) {
	// 选择数据库和集合
	collection := mdb.MDB.Collection(constant.CNamePlayerCountryByIPStat)

	// 定义聚合管道
	// 定义聚合管道
	pipeline := []bson.D{
		{
			{Key: "$project", Value: bson.D{
				{Key: "playerRegisterCountry", Value: bson.D{{Key: "$objectToArray", Value: "$playerRegisterCountry"}}},
			}},
		},
		{

			{Key: "$unwind", Value: "$playerRegisterCountry"},
		},
		{
			{Key: "$group", Value: bson.D{
				{Key: "_id", Value: "$playerRegisterCountry.k"},
				{Key: "totalValue", Value: bson.D{{Key: "$sum", Value: "$playerRegisterCountry.v"}}},
			}},
		},
		{
			{Key: "$project", Value: bson.D{
				{Key: "_id", Value: 0},
				{Key: "countryKey", Value: "$_id"},
				{Key: "totalValue", Value: 1},
			}},
		},
	}

	// 执行聚合查询
	cursor, err := collection.Aggregate(context.TODO(), pipeline)
	if err != nil {
		mhayaLogger.Warnf("FindUserCountryCount Aggregate error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}
	defer cursor.Close(context.TODO())

	// 遍历查询结果
	var results []bson.M
	if err := cursor.All(context.TODO(), &results); err != nil {
		mhayaLogger.Warnf("FindUserCountryCount All error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	var totalIPCount int64
	var data []*entity.UserCountryDetail
	// 将结果转换为 UserCountryDetail
	for _, r := range results {
		var resp entity.UserCountryDetail
		resp.Country = r["countryKey"].(string)
		resp.IPCount = int(r["totalValue"].(int32))
		totalIPCount += int64(resp.IPCount)
		data = append(data, &resp)
	}
	for _, v := range data {
		// 保留小数点后两位
		v.Percentage = math.Round(float64(v.IPCount)/float64(totalIPCount)*10000) / 100
	}

	// 根据阈值过滤结果
	otherCount := 0
	otherPercentage := 0.00
	filteredResults := make([]*entity.UserCountryDetail, 0)
	threshold := 1.00
	for _, r := range data {
		if r.Percentage >= threshold {
			filteredResults = append(filteredResults, r)
			// 保留小数点后两位
			r.Percentage = math.Round(r.Percentage*100) / 100
			otherPercentage += r.Percentage
		} else {
			otherCount += r.IPCount
		}
	}
	// 将其他国家添加到过滤后的结果中
	if otherCount > 0 {
		p := 100.00 - math.Round(otherPercentage*100)/100
		filteredResults = append(filteredResults, &entity.UserCountryDetail{
			Country:    "other",
			IPCount:    otherCount,
			Percentage: math.Round(p*100) / 100,
		})
	}
	return &entity.UserCountryResp{
		Details: filteredResults,
	}, nil

}

// FindUserRetention UserRetentionResp 用户留存率
// 1. 获取指定日期范围内的注册用户数量
// 2. 获取指定日期范围内的活跃用户数量
// 3. 计算留存率
// 4. 返回结果
func (s *Synthesis) FindUserRetention(req entity.UserRetentionReq) (*entity.UserRetentionResp, *code.Result) {
	playerPreserve := models.GetPlayerPreserve(req.StartTime, req.EndTime)
	// 查询数据
	var results []*entity.UserRetentionDetail

	for key, v := range playerPreserve {
		var retention entity.Retention
		for _, vv := range v {
			if vv.ID == 1 {
				retention.Day1 = entity.DayRetention{
					LoggedIn:  vv.Ratio,
					LoginDate: key,
				}
			}
			if vv.ID == 3 {
				retention.Day3 = entity.DayRetention{
					LoggedIn:  vv.Ratio,
					LoginDate: key,
				}
			}
			if vv.ID == 7 {
				retention.Day7 = entity.DayRetention{
					LoggedIn:  vv.Ratio,
					LoginDate: key,
				}
			}
			if vv.ID == 14 {
				retention.Day14 = entity.DayRetention{
					LoggedIn:  vv.Ratio,
					LoginDate: key,
				}
			}
			if vv.ID == 30 {
				retention.Day30 = entity.DayRetention{
					LoggedIn:  vv.Ratio,
					LoginDate: key,
				}
			}
		}

		results = append(results, &entity.UserRetentionDetail{
			RegistrationDate: key,
			RetentionData:    retention,
		})
	}

	return &entity.UserRetentionResp{
		Details: results,
	}, nil
}

// FindUserLevel 用户等级统计
func (s *Synthesis) FindUserLevel() (*entity.UserLevelCountResp, *code.Result) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()
	collection := mdb.MDB.Collection(constant.CNamePlayerLevelStat)

	// 查询所有文档
	cursor, err := collection.Find(ctx, bson.M{})
	if err != nil {
		mhayaLogger.Warnf("FindUserLevel Find error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}
	defer cursor.Close(ctx)

	var results []*entity.UserLevelCountDetail
	var reData []*models.PlayerLevelStat
	for cursor.Next(ctx) {
		var result models.PlayerLevelStat
		if err := cursor.Decode(&result); err != nil {
			mhayaLogger.Warnf("FindUserLevel Decode error:%v", err)
			return nil, common.NewResult(code.InternalError)
		}
		reData = append(reData, &result)
	}
	if err := cursor.Err(); err != nil {
		mhayaLogger.Warnf("FindUserLevel cursor error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	dataMap := make(map[string]int)
	for _, v := range reData {
		for key, v1 := range v.ServerLevel {
			dataMap[key] += v1
		}
	}

	for k, v := range dataMap {
		results = append(results, &entity.UserLevelCountDetail{
			Level:     cast.ToInt(k),
			UserCount: v,
		})
	}

	return &entity.UserLevelCountResp{
		Details: results,
	}, nil
}

func (s *Synthesis) InsertRecord(param model.UserOperationLog) {
	mhayaLogger.Warnf("InsertRecord param:%#v", param)

	record := new(model.UserOperationLog)
	collection := mdb.MDB.Collection(record.TableName())

	insertData := bson.M{}
	insertData["user_name"] = param.Username
	insertData["role_id"] = param.RoleId
	insertData["url"] = param.Path
	insertData["method"] = param.Method
	insertData["status_code"] = param.StatusCode
	insertData["dur"] = param.Dur
	insertData["client_ip"] = param.ClientIP
	insertData["error_message"] = param.ErrorMessage
	insertData["created_at"] = mhayaTime.Now().Unix()

	_, err := collection.InsertOne(context.Background(), insertData)
	if err != nil {
		mhayaLogger.Warnf("InsertRecord InsertOne error:%v", err)
		return
	}
}

func (s *Synthesis) RecordList(req entity.RecordListReq) (*entity.RecordListResp, *code.Result) {
	record := new(model.UserOperationLog)
	collection := mdb.MDB.Collection(record.TableName())

	// 构建过滤器
	filter := bson.M{}

	if req.UserName != "" {
		filter["userName"] = req.UserName
	}
	if req.RoleId != "" {
		filter["role_id"] = req.RoleId
	}
	if req.ID != "" {
		id, err := primitive.ObjectIDFromHex(req.ID)
		if err != nil {
			mhayaLogger.Warnf("RecordList ObjectIDFromHex error:%v, req.ID:%s", err, req.ID)
			return nil, common.NewResult(code.ParamError)
		}

		filter["id"] = id
	}

	if req.StartTime != 0 {
		filter["createAt"] = bson.M{
			"$gte": req.StartTime,
			"$lte": req.EndTime,
		}
	}

	// 设置分页选项
	findOptions := options.Find()
	findOptions.SetSkip(int64((req.Page - 1) * req.Size))
	findOptions.SetLimit(int64(req.Size))
	findOptions.SetSort(bson.D{{"created_at", -1}})

	// 获取总数total
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()
	count, err := collection.CountDocuments(ctx, filter)
	if err != nil {
		mhayaLogger.Warnf("RecordList CountDocuments error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	// 查询数据
	var results []*entity.RecordListDetail
	cursor, err := collection.Find(ctx, filter, findOptions)
	if err != nil {
		mhayaLogger.Warnf("RecordList Find error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}
	defer cursor.Close(ctx)

	// 解析结果
	for cursor.Next(ctx) {
		var result entity.RecordListDetail
		if err := cursor.Decode(&result); err != nil {
			mhayaLogger.Warnf("RecordList Decode error:%v", err)
			return nil, common.NewResult(code.InternalError)
		}
		results = append(results, &result)
	}

	if err := cursor.Err(); err != nil {
		mhayaLogger.Warnf("RecordList cursor error:%v", err)
		return nil, common.NewResult(code.InternalError)
	}

	return &entity.RecordListResp{
		Details: results,
		Total:   count,
	}, nil
}
