package cluster

import (
	"context"

	"github.com/tidbcloud/pkgv2/db"

	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cluster"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type clusterPausePlanRepoImp struct {
	dbProvider db.Provider
}

func NewPausePlanRepo(dbProvider db.Provider) cluster.PausePlanRepo {
	return clusterPausePlanRepoImp{dbProvider: dbProvider}
}

func (c clusterPausePlanRepoImp) LoadByClusterId(
	ctx context.Context,
	clusterId uint64,
) (*entity.ClusterPausePlan, bizerr.BizError) {
	rdb := c.dbProvider.ReadDB(ctx)

	pausePlan := &schema.ClusterPausePlan{}
	if err := rdb.Model(&schema.ClusterPausePlan{}).
		Where("cluster_id = ?", clusterId).
		Take(pausePlan).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "load cluster pause plan by cluster id %d", clusterId)
	}

	en, err := cvtClusterPausePlanModelToEntity(pausePlan)
	if err != nil {
		return nil, bizerr.WrapError(err, "convert to cluster pause plan entity, cluster id %d", clusterId)
	}

	return en, nil
}

func (c clusterPausePlanRepoImp) LoadMany(
	ctx context.Context,
	clusterIds []uint64,
) (map[uint64]*entity.ClusterPausePlan, bizerr.BizError) {
	if len(clusterIds) == 0 {
		return map[uint64]*entity.ClusterPausePlan{}, nil
	}

	rdb := c.dbProvider.ReadDB(ctx)

	var pausePlans []*schema.ClusterPausePlan
	if err := rdb.Model(&schema.ClusterPausePlan{}).
		Where("cluster_id in (?)", clusterIds).Find(&pausePlans).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "load cluster pause plans by cluster ids %v", clusterIds)
	}

	ens := make(map[uint64]*entity.ClusterPausePlan, len(pausePlans))
	for _, p := range pausePlans {
		en, err := cvtClusterPausePlanModelToEntity(p)
		if err != nil {
			return nil, bizerr.WrapError(err, "convert to cluster pause plan entity, cluster id %d", p.ClusterID)
		}
		ens[p.ClusterID] = en
	}
	return ens, nil
}

func (c clusterPausePlanRepoImp) DeleteByClusterId(ctx context.Context, clusterId uint64) bizerr.BizError {
	rdb := c.dbProvider.WriteDB(ctx)

	if err := rdb.Where("cluster_id = ?", clusterId).Delete(&schema.ClusterPausePlan{}).Error; err != nil {
		return bizerr.WrapGormError(err, "delete cluster pause plan by cluster id %d", clusterId)
	}

	return nil
}

func (c clusterPausePlanRepoImp) Save(
	ctx context.Context,
	en *entity.ClusterPausePlan,
	clusterId uint64,
) bizerr.BizError {
	wdb := c.dbProvider.WriteDB(ctx)

	model, err := cvtClusterPausePlanEntityToModel(en, clusterId)
	if err != nil {
		return bizerr.WrapError(err, "convert to cluster pause plan model, cluster id %d", clusterId)
	}

	if err := wdb.Save(model).Error; err != nil {
		return bizerr.WrapGormError(err, "save cluster pause plan, cluster id %d", clusterId)
	}

	return nil
}
