package adapterimpl

import (
	"context"
	"strconv"

	"github.com/tidbcloud/serverless-service/idl/pbgen/proto/serverless"
	"google.golang.org/protobuf/proto"

	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/adapter"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/infra/adapterimpl/cli"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type serverlessFacadeImp struct{}

func NewServerless() adapter.ServerlessService {
	return &serverlessFacadeImp{}
}

func (f serverlessFacadeImp) SetSpendLimit(
	ctx context.Context,
	clusterIdStr string,
	tenantId uint64,
	spendLimit uint32,
	region string,
	enhancedEncryptionEnabled bool,
	validateOnly bool,
) error {
	clusterId, err := strconv.ParseUint(clusterIdStr, 10, 64)
	if err != nil {
		return bizerr.WrapError(err, "invalid cluster id")
	}

	req := &serverless.SetSpendLimitReq{
		OrgId:                     tenantId,
		ClusterId:                 clusterId,
		SpendLimit:                spendLimit,
		Region:                    region,
		EnhancedEncryptionEnabled: proto.Bool(enhancedEncryptionEnabled),
		ValidateOnly:              proto.Bool(validateOnly),
	}
	return cli.SetSpendLimit(ctx, req)
}

func (f serverlessFacadeImp) GetSpendLimit(
	ctx context.Context,
	clusterIdStr string,
	tenantId uint64,
) (*globalserverlessv1.SpendLimit, error) {
	clusterId, err := strconv.ParseUint(clusterIdStr, 10, 64)
	if err != nil {
		return nil, bizerr.WrapError(err, "invalid cluster id")
	}

	req := &serverless.GetSpendLimitReq{
		OrgId:     tenantId,
		ClusterId: clusterId,
	}
	resp, err := cli.GetSpendLimit(ctx, req)
	if err != nil {
		return nil, err
	}

	return &globalserverlessv1.SpendLimit{
		Monthly:    resp.GetSpendLimit(),
		FreeCredit: resp.GetFreeCredit(),
	}, nil
}

func (f serverlessFacadeImp) DeleteSpendLimit(
	ctx context.Context,
	clusterIdStr string,
	tenantId uint64,
) error {
	clusterId, err := strconv.ParseUint(clusterIdStr, 10, 64)
	if err != nil {
		return bizerr.WrapError(err, "invalid cluster id")
	}

	req := &serverless.DeleteSpendLimitReq{
		OrgId:     tenantId,
		ClusterId: clusterId,
	}
	return cli.DeleteSpendLimit(ctx, req)
}

type fakeServerlessFacade struct{}

func NewFakeServerlessFacade() adapter.ServerlessService {
	return &fakeServerlessFacade{}
}

func (f fakeServerlessFacade) SetSpendLimit(
	ctx context.Context,
	clusterId string,
	tenantId uint64,
	spendLimit uint32,
	region string,
	enhancedEncryptionEnabled bool,
	validateOnly bool,
) error {
	if clusterId == "" || tenantId == 0 || region == "" {
		return bizerr.New(bizerr.ErrCodeParams, "invalid arguments")
	}

	if _, err := strconv.ParseUint(clusterId, 10, 64); err != nil {
		return bizerr.New(bizerr.ErrCodeParams, "invalid cluster id")
	}
	return nil
}

func (f fakeServerlessFacade) GetSpendLimit(
	ctx context.Context,
	clusterIdStr string,
	tenantId uint64,
) (*globalserverlessv1.SpendLimit, error) {
	if clusterIdStr == "" || tenantId == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "invalid arguments")
	}

	if _, err := strconv.ParseUint(clusterIdStr, 10, 64); err != nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "invalid cluster id")
	}

	return &globalserverlessv1.SpendLimit{
		Monthly: 1,
	}, nil
}

func (f fakeServerlessFacade) DeleteSpendLimit(
	ctx context.Context,
	clusterIdStr string,
	tenantId uint64,
) error {
	return nil
}
