package privatelink

import (
	"strconv"
	"strings"

	"gorm.io/gorm"
	"k8s.io/utils/ptr"

	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"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/enum"
)

func privatelinkServiceEnToModel(service *entity.PrivateLinkService) *schema.PrivateLinkService {
	return &schema.PrivateLinkService{
		Model: gorm.Model{
			ID: uint(service.PrivateLinkServiceID),
		},
		ClusterId:      service.ClusterId,
		TidbGroupId:    service.TidbGroupId,
		ServiceName:    service.ServiceName,
		ServiceHost:    service.ServiceDnsName,
		ServicePort:    int(service.ServicePort),
		AvailableZones: strings.Join(service.AvailableZones, ","),
	}
}

func privatelinkServiceModelToEn(
	service *schema.PrivateLinkService,
	region *schema.Region,
	provider *schema.Provider,
) (*entity.PrivateLinkService, bizerr.BizError) {
	en := &entity.PrivateLinkService{
		PrivateLinkService: &globalngv1.PrivateLinkService{
			ClusterId:      service.ClusterId,
			TidbGroupId:    service.TidbGroupId,
			ServiceName:    service.ServiceName,
			ServiceDnsName: service.ServiceHost,
			ServicePort:    int32(service.ServicePort),
			AvailableZones: strings.Split(service.AvailableZones, ","),
		},
		PrivateLinkServiceID: uint64(service.ID),
	}

	if provider == nil {
		return nil, bizerr.New(bizerr.ErrCodeDB, "provider is nil")
	}
	providerId, err := enum.FromString[globalcommonv1.CloudProvider_Name](provider.Name)
	if err != nil {
		return nil, bizerr.WrapError(err, "convert cloud provider")
	}
	en.CloudProviderId = globalcommonv1.CloudProvider_Name(providerId)

	if region == nil {
		return nil, bizerr.New(bizerr.ErrCodeDB, "region is nil")
	}

	regionId, err := enum.RegionFromString(provider.Name, region.RegionName)
	if err != nil || regionId == globalcommonv1.Region_NAME_UNSPECIFIED {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region: %s", region.RegionName)
	}

	en.RegionId = regionId
	return en, nil
}

func privatelinkConnectionEnToModel(
	connection *entity.PrivateLinkConnection,
	service *schema.PrivateLinkService,
	id uint64,
) *schema.PrivateLinkConnection {
	return &schema.PrivateLinkConnection{
		Model: gorm.Model{
			ID: uint(id),
		},
		ClusterId:            connection.ClusterId,
		EndpointId:           connection.EndpointId,
		TidbGroupId:          connection.TidbGroupId,
		PrivateLinkServiceId: uint64(service.ID),
		EndpointType:         strings.ToLower(connection.EndpointType.String()),
		DefaultDomainName:    connection.GetPrivateDomainName(),
		PrivateIpAddress:     ptr.To(connection.PrivateIpAddress),
	}
}

func privatelinkConnectionModelToEn(
	connection *schema.PrivateLinkConnection,
	region *schema.Region,
	provider *schema.Provider,
) (*entity.PrivateLinkConnection, bizerr.BizError) {
	en := &entity.PrivateLinkConnection{
		PrivateLinkConnection: &globalngv1.PrivateLinkConnection{
			PrivateLinkConnectionId: strconv.FormatUint(uint64(connection.ID), 10),
			ClusterId:               connection.ClusterId,
			EndpointId:              connection.EndpointId,
			TidbGroupId:             connection.TidbGroupId,
			PrivateDomainName:       connection.DefaultDomainName,
		},
		PrivateLinkConnectionID: uint64(connection.ID),
		PrivateLinkServiceID:    connection.PrivateLinkServiceId,
	}
	if connection.PrivateIpAddress != nil {
		en.PrivateIpAddress = *connection.PrivateIpAddress
	}
	endpointType, err := enum.FromString[globalngv1.PrivateLinkConnection_EndpointType](
		strings.ToUpper(connection.EndpointType),
	)
	if err != nil {
		return nil, bizerr.WrapError(err, "convert endpoint type")
	}
	en.EndpointType = globalngv1.PrivateLinkConnection_EndpointType(endpointType)

	if region == nil {
		return nil, bizerr.New(bizerr.ErrCodeDB, "region is nil")
	}

	regionId, err := enum.RegionFromString(provider.Name, region.RegionName)
	if err != nil || regionId == globalcommonv1.Region_NAME_UNSPECIFIED {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region: %s", region.Name)
	}

	en.RegionId = regionId

	if provider == nil {
		return nil, bizerr.New(bizerr.ErrCodeDB, "provider is nil")
	}
	providerId, err := enum.FromString[globalcommonv1.CloudProvider_Name](provider.Name)
	if err != nil {
		return nil, bizerr.WrapError(err, "convert provider")
	}
	en.CloudProviderId = globalcommonv1.CloudProvider_Name(providerId)

	return en, nil
}
