package region

import (
	"context"
	"errors"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	regionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *service) ListCloudProviders(
	ctx context.Context,
	req *globalngv1.ListCloudProvidersRequest,
) ([]*entity.CloudProvider, bizerr.BizError) {
	// default state is empty, which means all states are returned
	state := ""
	if req.State != globalcommonv1.CloudProvider_STATE_UNSPECIFIED {
		state = req.State.String()
	}
	cloudProviders, err := s.regionRepo.ListCloudProviders(ctx, regionrepo.Filter{
		ServicePlan: req.ServicePlan,
		TenantId:    req.OrganizationId,
		State:       state,
	})
	if err != nil {
		return nil, err
	}
	return cloudProviders, nil
}

func (s *service) RegisterCloudProvider(
	ctx context.Context,
	req *globalngv1.RegisterCloudProviderRequest,
) (*entity.CloudProvider, bizerr.BizError) {
	if req.GetCloudProvider() == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cloud provider is required")
	}

	cp := &entity.CloudProvider{
		CloudProvider: req.GetCloudProvider(),
	}

	if err := validCloudProvider(cp); err != nil {
		return nil, err
	}

	if err := s.transaction.Transaction(ctx, func(ctx context.Context) error {
		// check if cloud provider already exists
		_, err := s.regionRepo.GetCloudProviderById(ctx, cp.GetId(), cp.GetServicePlan())
		if err == nil {
			return bizerr.New(bizerr.ErrCodeRecordExist, "cloud provider %s already exists", cp.GetId())
		}

		// if error code is not ErrCodeRecordNotFound, means unexpected error
		var be bizerr.BizError
		ok := errors.As(err, &be)
		if ok && be.ErrCode() != bizerr.ErrCodeRecordNotFound {
			return err
		}

		// save cloud provider
		err = s.regionRepo.SaveCloudProvider(ctx, cp)
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return nil, bizerr.WrapError(err, "register cloud provider failed")
	}

	return cp, nil
}

func validCloudProvider(cp *entity.CloudProvider) bizerr.BizError {
	if cp.GetId() == globalcommonv1.CloudProvider_NAME_UNSPECIFIED {
		return bizerr.New(bizerr.ErrCodeParams, "cloud provider is required")
	}

	if cp.GetDisplayName() == "" {
		return bizerr.New(bizerr.ErrCodeParams, "display name is required")
	}

	return nil
}
