package cluster

import (
	"context"

	"github.com/tidbcloud/pkgv2/db"
	"google.golang.org/protobuf/types/known/timestamppb"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/quota"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type UpdateTenantQuotaParams struct {
	TenantID  uint64
	Component globaldedicatedv1.ComponentType
	Quota     uint32
}

type UpdateTenantQuotaSvc interface {
	Execute(ctx context.Context, params *UpdateTenantQuotaParams) bizerr.BizError
}

type updateTenantQuotaSvc struct {
	quotaRepo quota.TenantClusterComponentQuotaRepo

	transaction db.Transactioner
}

func NewUpdateTenantQuotaSvc(
	quotaRepo quota.TenantClusterComponentQuotaRepo,
	transaction db.Transactioner,
) UpdateTenantQuotaSvc {
	return &updateTenantQuotaSvc{
		quotaRepo:   quotaRepo,
		transaction: transaction,
	}
}

func (svc *updateTenantQuotaSvc) Execute(ctx context.Context, params *UpdateTenantQuotaParams) bizerr.BizError {
	ctx, span := tracer.Start(ctx, "Domain.updateTenantQuotaSvc")
	defer span.End()

	if params.TenantID == 0 {
		return bizerr.New(bizerr.ErrCodeParams, "invalid tenant id")
	}

	err := svc.transaction.Transaction(ctx, func(ctx context.Context) error {
		var q *entity.TenantComponentQuota
		quotas, berr := svc.quotaRepo.Query(ctx, quota.TenantQuotaFilter{
			TenantID:  params.TenantID,
			Component: params.Component,
		})
		if berr != nil {
			return berr
		}

		switch len(quotas) {
		case 0:
			q = &entity.TenantComponentQuota{
				TenantID:      params.TenantID,
				ComponentName: params.Component,
				Quota:         params.Quota,
				CreateTime:    timestamppb.Now(),
			}
		case 1:
			q = quotas[0]
		default:
			return bizerr.New(bizerr.ErrCodeUnknown, "duplicate quota records")
		}

		q.Quota = params.Quota

		return svc.quotaRepo.Save(ctx, q)
	})
	if err != nil {
		return bizerr.WrapError(err, "failed to update tenant quota")
	}

	return nil
}
