package privatelink

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/repository"
)

func TestResolveMSKRouteAcceptsRegionEnumString(t *testing.T) {
	svc := &service{
		regionRepo: &fakeRegionRepo{
			region: &entity.Region{
				Id:              globalcommonv1.Region_AWS_US_EAST_1,
				CloudProviderId: globalcommonv1.CloudProvider_AWS,
				State:           globalcommonv1.Region_ACTIVE,
				IsPublic:        true,
				ServiceAddress:  "regional-service",
			},
		},
	}

	projectID, clusterID, region, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		globalcommonv1.Region_AWS_US_EAST_1.String(),
		"shared-k8s",
	)

	require.NoError(t, err)
	require.Zero(t, projectID)
	require.Empty(t, clusterID)
	require.Equal(t, globalcommonv1.Region_AWS_US_EAST_1, region.GetId())
}

func TestResolveMSKRouteAcceptsBareAWSRegionName(t *testing.T) {
	svc := &service{
		regionRepo: &fakeRegionRepo{
			region: &entity.Region{
				Id:              globalcommonv1.Region_AWS_US_EAST_1,
				CloudProviderId: globalcommonv1.CloudProvider_AWS,
				State:           globalcommonv1.Region_ACTIVE,
				IsPublic:        true,
				ServiceAddress:  "regional-service",
			},
		},
	}

	_, _, region, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		"us-east-1",
		"shared-k8s",
	)

	require.NoError(t, err)
	require.Equal(t, globalcommonv1.Region_AWS_US_EAST_1, region.GetId())
}

func TestResolveMSKRouteSkipsEmptyServiceAddress(t *testing.T) {
	region := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        true,
		ServiceAddress:  "regional-service",
	}
	svc := &service{regionRepo: &fakeRegionRepo{regions: []*entity.Region{
		{Id: region.Id, CloudProviderId: region.CloudProviderId},
		region,
	}}}

	_, _, resolved, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		"us-east-1",
		"shared-k8s",
	)

	require.NoError(t, err)
	require.Same(t, region, resolved)
}

func TestResolveMSKRouteDeduplicatesServiceAddressAcrossPlans(t *testing.T) {
	starter := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		ServicePlan:     globalcommonv1.ServicePlan_Starter,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        true,
		ServiceAddress:  "regional-service",
	}
	essential := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		ServicePlan:     globalcommonv1.ServicePlan_Essential,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        true,
		ServiceAddress:  "regional-service",
	}
	svc := &service{regionRepo: &fakeRegionRepo{regions: []*entity.Region{starter, essential}}}

	_, _, resolved, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		"us-east-1",
		"shared-k8s",
	)

	require.NoError(t, err)
	require.Contains(t, []*entity.Region{starter, essential}, resolved)
	require.Equal(t, "regional-service", resolved.GetServiceAddress())
}

func TestResolveMSKRouteRejectsMultipleServiceAddresses(t *testing.T) {
	svc := &service{regionRepo: &fakeRegionRepo{regions: []*entity.Region{
		{
			Id:              globalcommonv1.Region_AWS_US_EAST_1,
			CloudProviderId: globalcommonv1.CloudProvider_AWS,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
			State:           globalcommonv1.Region_ACTIVE,
			IsPublic:        true,
			ServiceAddress:  "regional-service-a",
		},
		{
			Id:              globalcommonv1.Region_AWS_US_EAST_1,
			CloudProviderId: globalcommonv1.CloudProvider_AWS,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
			State:           globalcommonv1.Region_ACTIVE,
			IsPublic:        true,
			ServiceAddress:  "regional-service-b",
		},
	}}}

	_, _, _, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		"us-east-1",
		"shared-k8s",
	)

	require.Error(t, err)
	require.Contains(t, err.Error(), "multiple regional service addresses")
}

func TestResolveMSKRouteRejectsMissingServiceAddress(t *testing.T) {
	svc := &service{regionRepo: &fakeRegionRepo{regions: []*entity.Region{
		{
			Id:              globalcommonv1.Region_AWS_US_EAST_1,
			CloudProviderId: globalcommonv1.CloudProvider_AWS,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
			State:           globalcommonv1.Region_ACTIVE,
			IsPublic:        true,
		},
	}}}

	_, _, _, err := svc.resolveMSKRoute(
		context.Background(),
		"",
		globalcommonv1.CloudProvider_AWS,
		1,
		globalcommonv1.ServicePlan_Starter,
		"us-east-1",
		"shared-k8s",
	)

	require.Error(t, err)
	require.Contains(t, err.Error(), "regional service for provider aws, region us-east-1, service plan Starter is not available")
}

func TestResolveMSKRoutePrefersTenantPrivateRegion(t *testing.T) {
	public := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		ServicePlan:     globalcommonv1.ServicePlan_Starter,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        true,
		ServiceAddress:  "public-regional-service",
	}
	private := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		ServicePlan:     globalcommonv1.ServicePlan_Starter,
		State:           globalcommonv1.Region_ACTIVE,
		OpenedTenantIds: []uint64{42},
		ServiceAddress:  "private-regional-service",
	}
	svc := &service{regionRepo: &fakeRegionRepo{regions: []*entity.Region{public, private}}}

	_, _, resolved, err := svc.resolveMSKRoute(
		context.Background(), "", globalcommonv1.CloudProvider_AWS, 42,
		globalcommonv1.ServicePlan_Starter, "us-east-1", "shared-k8s",
	)

	require.NoError(t, err)
	require.Same(t, private, resolved)
}

type fakeRegionRepo struct {
	region  *entity.Region
	regions []*entity.Region
}

func (r *fakeRegionRepo) Save(context.Context, *entity.Region) (*entity.Region, error) {
	panic("unused")
}

func (r *fakeRegionRepo) LoadRegions(
	_ context.Context,
	filter *repository.CloudRegionFilter,
) ([]*entity.Region, error) {
	if r.regions != nil {
		if len(filter.CloudProviderNames) == 1 &&
			len(filter.Names) == 1 &&
			filter.CloudProviderNames[0] == r.regions[0].GetCloudProviderId() &&
			filter.Names[0] == r.regions[0].GetId() {
			return r.regions, nil
		}
		return nil, nil
	}
	if len(filter.CloudProviderNames) == 1 &&
		filter.CloudProviderNames[0] == r.region.GetCloudProviderId() &&
		len(filter.Names) == 1 &&
		filter.Names[0] == r.region.GetId() {
		return []*entity.Region{r.region}, nil
	}
	return nil, nil
}

func (r *fakeRegionRepo) Delete(context.Context, *entity.Region) error {
	panic("unused")
}
