package common

import (
	"context"
	"encoding/json"
	"time"

	"github.com/perfect-panel/server/internal/config"
	"github.com/perfect-panel/server/internal/model/server"
	"github.com/perfect-panel/server/internal/model/user"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/logger"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
)

type GetStatLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// Get Tos
func NewGetStatLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetStatLogic {
	return &GetStatLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetStatLogic) GetStat() (resp *types.GetStatResponse, err error) {
	respJson, err := l.svcCtx.Redis.Get(l.ctx, config.CommonStatCacheKey).Result()
	if err == nil {
		err = json.Unmarshal([]byte(respJson), resp)
		if err == nil {
			return
		}
	}
	var u int64
	err = l.svcCtx.DB.Model(&user.User{}).Where("enable = 1").Count(&u).Error
	if err != nil {
		l.Logger.Error("[GetStatLogic] get user count failed: ", logger.Field("error", err.Error()))
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get user count failed: %v", err.Error())
	}
	if u > 100 {
		u -= u % 100
	} else if u > 10 {
		u -= u % 10
	} else {
		u = 1
	}
	var n int64
	err = l.svcCtx.DB.Model(&server.Server{}).Where("enable = 1").Count(&n).Error
	if err != nil {
		l.Logger.Error("[GetStatLogic] get server count failed: ", logger.Field("error", err.Error()))
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get server count failed: %v", err.Error())
	}
	var nodeaddr []string
	err = l.svcCtx.DB.Model(&server.Server{}).Where("enable = 1").Pluck("server_addr", &nodeaddr).Error
	if err != nil {
		l.Logger.Error("[GetStatLogic] get server_addr failed: ", logger.Field("error", err.Error()))
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get server_addr failed: %v", err.Error())
	}

	country := 0

	protocolDict := make(map[string]struct{})
	var protocol []string
	l.svcCtx.DB.Model(&server.Server{}).Where("enable = true").Pluck("protocol", &protocol)
	for _, p := range protocol {
		protocolDict[p] = struct{}{}
	}
	protocol = nil
	for p := range protocolDict {
		protocol = append(protocol, p)
	}
	resp = &types.GetStatResponse{
		User:         u,
		Node:         n,
		Country:      int64(country),
		Protocol:     protocol,
		OnlineDevice: l.svcCtx.DeviceManager.GetOnlineDeviceCount(),
	}
	val, _ := json.Marshal(*resp)
	_ = l.svcCtx.Redis.Set(l.ctx, config.CommonStatCacheKey, string(val), time.Duration(3600)*time.Second).Err()
	return resp, nil
}
