package svc

import (
	"context"
	"gitea.youtukeji.com.cn/youtu/youtu_grpc/app/ranking_service/internal/gen/dao/query"
	"gitea.youtukeji.com.cn/youtu/youtu_grpc/app/ranking_service/internal/logic/rankings"
	"gitea.youtukeji.com.cn/youtu/youtu_grpc/app/user_service/userservice"
	"gitea.youtukeji.com.cn/youtu/youtu_grpc/pkg/config"
	"gitea.youtukeji.com.cn/youtu/youtu_grpc/pkg/my_gorm"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"github.com/zeromicro/go-zero/core/conf"
	"github.com/zeromicro/go-zero/core/discov"
	"github.com/zeromicro/go-zero/zrpc"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type ServiceContext struct {
	Config            config.Config
	Query             *query.Query
	RedisRanking      *rankings.Ranking
	UserServiceClient userservice.UserService
}

func NewServiceContext(c config.Config) *ServiceContext {
	svc := &ServiceContext{
		Config: c,
	}

	//初始化redis client
	redisClient := redis.NewClient(&redis.Options{
		Addr: c.Redis[0].Host,
	})
	//初始化数据库
	db, err := my_gorm.NewDBWithCache(mysql.Open(c.Mysql), &gorm.Config{}, redisClient)
	if err != nil {
		panic(err)
	}

	svc.Query = query.Use(db)

	// 初始化用户客户端
	clientConf := zrpc.RpcClientConf{}
	err = conf.FillDefault(&clientConf) // 填充默认值,比如 trace 透传等,参考服务配置说明
	if err != nil {
		panic(err)
	}
	clientConf.Token = "user_service.rpc.key"
	clientConf.App = "user_service.rpc"
	clientConf.Etcd = discov.EtcdConf{ // 通过 etcd 服务发现
		Hosts: []string{viper.GetString(config.EtcdAddrKey)},
		Key:   "user_service.rpc",
	}

	svc.UserServiceClient = userservice.NewUserService(zrpc.MustNewClient(clientConf))

	//初始化排行榜对象
	svc.InitRankings(redisClient)

	return svc
}

func (svc *ServiceContext) InitRankings(redisClient *redis.Client) {
	//初始化排行榜对象
	svc.RedisRanking = rankings.NewRanking(redisClient)

	//获取所有不同的排行榜
	gs := svc.Query.GameScore
	r, err := gs.WithContext(context.TODO()).Select(gs.AppAccount, gs.T).Distinct().Find()
	if err != nil {
		panic(err)
	}
	//获取所有排行榜
	for _, ranking := range r {
		scores, err := gs.WithContext(context.TODO()).Where(gs.AppAccount.Eq(ranking.AppAccount), gs.T.Eq(ranking.T)).Find()
		if err != nil {
			panic(err)
		}
		data := make([]redis.Z, 0, len(scores))

		for _, score := range scores {
			data = append(data, redis.Z{
				Score:  float64(uint64(score.Score)<<32 + uint64(score.UpdatedAt.Unix())),
				Member: score.UserID,
			})
		}
		svc.RedisRanking.SetList(context.Background(), rankings.GetRankingsCacheKey(ranking.AppAccount, ranking.T), data...)
	}
}