package vpc

import (
	"context"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	cidrrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cidr"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/enum"
)

func (s *serviceImpl) CreateCidr(
	ctx context.Context,
	params *globaldedicatedv1.CreateCidrRequest,
) (*entity.CIDR, *ValidateOnlyResponse, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.CreateCidrSvc")
	defer span.End()

	project, err := s.accountCli.GetProject(ctx, params.GetProjectId())
	if err != nil {
		return nil, nil, err
	}

	cloudProviderName, rawErr := enum.FromString[globalcommonv1.CloudProvider_Name](params.CloudProviderName)
	if rawErr != nil {
		return nil, nil, bizerr.New(bizerr.ErrCodeParams, "invalid cloud provider")
	}

	regionName, rawErr := enum.FromString[globalcommonv1.Region_Name](params.RegionName)
	if rawErr != nil {
		return nil, nil, bizerr.New(bizerr.ErrCodeParams, "invalid region")
	}

	var (
		cidrEntity           *entity.CIDR
		validateOnlyResponse *ValidateOnlyResponse
	)
	err_ := s.transaction.Transaction(ctx, func(ctx context.Context) error {
		cloudProvider, err := s.regionRepo.GetCloudProviderById(
			ctx,
			globalcommonv1.CloudProvider_Name(cloudProviderName),
			project.TenantID,
		)
		if err != nil {
			return err
		}
		region, err := s.regionRepo.SelectRegionById(ctx, globalcommonv1.Region_Name(regionName), project.TenantID)
		if err != nil {
			return err
		}

		err = entity.CheckCloudProviderAndRegionAvailableForTenant(cloudProvider, region, project.TenantID)
		if err != nil {
			return err
		}

		cidrFilter := &cidrrepo.Filter{
			IDs:         nil, // leave it empty
			ProjectIDs:  []uint64{params.GetProjectId()},
			RegionNames: []entity.RegionName{region.Id},
		}
		count, err := s.cidrRepo.Count(ctx, cidrFilter)
		if err != nil {
			return err
		}
		if count > 0 {
			return bizerr.New(bizerr.ErrCodeParams, "CIDR already exists")
		}

		if params.GetCidr() == "" {
			defaultCidr, err := s.GetDefaultCidr(ctx, &globaldedicatedv1.GetDefaultCidrRequest{
				CloudProviderName: params.GetCloudProviderName(),
				RegionName:        params.GetRegionName(),
				ProjectId:         params.GetProjectId(),
			})
			if err != nil {
				return err
			}
			params.Cidr = defaultCidr.Cidr
		}

		cidrMask, err := s.helper.ValidateCIDR(
			params.GetCidr(),
			globalcommonv1.CloudProvider_Name(cloudProviderName),
			project.TenantID,
			project.ID,
		)
		if err != nil {
			return err
		}

		if params.ValidateOnly {
			validateOnlyResponse, err = s.helper.BuildValidateOnlyResponse(
				ctx,
				globalcommonv1.CloudProvider_Name(cloudProviderName),
				params.GetCidr(),
				cidrMask,
				project,
				nil,
			)
			if err != nil {
				return err
			}
			return nil
		}

		cidrID := s.idGeneratorFacade.MustNew()
		cidrEntity = &entity.CIDR{
			ID:          cidrID,
			ProjectID:   params.GetProjectId(),
			TenantID:    project.TenantID,
			BasicRegion: entity.RegionToBasicRegion(region),
			CIDR:        params.GetCidr(),
		}
		err = s.cidrRepo.Create(ctx, cidrEntity)
		if err != nil {
			return err
		}

		return nil
	})
	if err_ != nil {
		return nil, nil, bizerr.WrapError(err_, "failed to create CIDR")
	}

	return cidrEntity, validateOnlyResponse, nil
}
