package dbutil

import (
	"context"

	"github.com/tidbcloud/metrics-server/central/db"
	"github.com/tidbcloud/metrics-server/central/db/entity"
	"go.uber.org/multierr"
)

func NewClusterRepo(
	dbProvider db.Provider) *clusterRepo {
	return &clusterRepo{
		dbProvider: dbProvider,
	}
}

type clusterRepo struct {
	dbProvider db.Provider
}

func (imp *clusterRepo) DeleteClusterAndMakeFinalBackup(ctx context.Context, clusterID entity.ID) error {
	wdb := imp.dbProvider.WriteDB(ctx)
	return DeleteClusterAndMakeFinalBackup(ctx, wdb, clusterID)
}

func (imp *clusterRepo) DeleteClusters(ctx context.Context, clusterIDs []entity.ID) error {
	wdb := imp.dbProvider.WriteDB(ctx)
	var errs error
	for _, each := range clusterIDs {
		errs = multierr.Append(errs, DeleteCluster(ctx, wdb, each))
	}
	return errs
}

func (imp *clusterRepo) DeleteBackupsByClusterIDs(ctx context.Context, clusterIDs []entity.ID) error {
	wdb := imp.dbProvider.WriteDB(ctx)
	return DeleteBackupsByClusterIDs(wdb, clusterIDs)
}

func (imp *clusterRepo) QueryClusters(ctx context.Context, filter ClusterFilter) ([]entity.Cluster, error) {
	rdb := imp.dbProvider.ReadDB(ctx)
	return FindClusters(rdb, filter)
}

func NewClusterTrafficUsageRepoRepo(
	dbProvider db.Provider) *clusterTrafficUsageRepo {
	return &clusterTrafficUsageRepo{
		dbProvider: dbProvider,
	}
}

type clusterTrafficUsageRepo struct {
	dbProvider db.Provider
}

func (imp *clusterTrafficUsageRepo) LoadByPeriod(ctx context.Context, clusterID entity.ID, period string) (*entity.ClusterTrafficUsage, error) {
	rdb := imp.dbProvider.ReadDB(ctx)
	usage := &entity.ClusterTrafficUsage{}
	err := rdb.Model(&entity.ClusterTrafficUsage{}).Where("cluster_id=? AND period=?", clusterID, period).First(usage).Error
	return usage, err
}

func (imp *clusterTrafficUsageRepo) Save(ctx context.Context, en *entity.ClusterTrafficUsage) error {
	wdb := imp.dbProvider.WriteDB(ctx)
	return wdb.Save(en).Error
}

func (imp *clusterTrafficUsageRepo) SumUsageByTenant(ctx context.Context, tenantID entity.ID, period string) (ingressUsage, egressUsage int64, err error) {
	rdb := imp.dbProvider.ReadDB(ctx)
	return SumClusterTrafficUsageByTenant(rdb, tenantID, period)
}

func NewTenantRepo(
	dbProvider db.Provider) *tenantRepo {
	return &tenantRepo{
		dbProvider: dbProvider,
	}
}

type tenantRepo struct {
	dbProvider db.Provider
}

func (imp *tenantRepo) Load(ctx context.Context, id entity.ID) (entity.Tenant, error) {
	rdb := imp.dbProvider.ReadDB(ctx)
	return GetTenantByID(rdb, id)
}

func NewUserRepo(
	dbProvider db.Provider) *userRepo {
	return &userRepo{
		dbProvider: dbProvider,
	}
}

type userRepo struct {
	dbProvider db.Provider
}

func (imp *userRepo) LoadByEmail(ctx context.Context, email string) (entity.User, error) {
	rdb := imp.dbProvider.ReadDB(ctx)
	return GetUserByEmail(rdb, email)
}
