package resourcepool

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func TestBuildCreateSharedPoolRequestMapsPdDeploymentMode(t *testing.T) {
	tests := []struct {
		name string
		in   globalngv1.PdDeploymentMode
		want clusterngv1beta.PDDeploymentMode
	}{
		{
			name: "unspecified rcu driven defaults to monolithic",
			in:   globalngv1.PdDeploymentMode_PD_DEPLOYMENT_MODE_UNSPECIFIED,
			want: clusterngv1beta.PDDeploymentMode_PD_DEPLOYMENT_MODE_MONOLITHIC,
		},
		{
			name: "microservice maps to microservice",
			in:   globalngv1.PdDeploymentMode_PD_DEPLOYMENT_MODE_MICROSERVICE,
			want: clusterngv1beta.PDDeploymentMode_PD_DEPLOYMENT_MODE_MICROSERVICE,
		},
		{
			name: "monolithic maps to monolithic",
			in:   globalngv1.PdDeploymentMode_PD_DEPLOYMENT_MODE_MONOLITHIC,
			want: clusterngv1beta.PDDeploymentMode_PD_DEPLOYMENT_MODE_MONOLITHIC,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := createResourcePoolRequestWithPdDeploymentMode(tt.in)

			sharedPoolReq, err := buildCreateSharedPoolRequest(req, 100, "cloud-identity", nil)

			require.NoError(t, err)
			assert.Equal(t, tt.want, sharedPoolReq.GetPdDeploymentMode())
		})
	}
}

func TestBuildCreateSharedPoolRequestRejectsUnknownPdDeploymentMode(t *testing.T) {
	req := createResourcePoolRequestWithPdDeploymentMode(globalngv1.PdDeploymentMode(999))

	_, err := buildCreateSharedPoolRequest(req, 100, "cloud-identity", nil)

	require.NotNil(t, err)
	assert.Equal(t, bizerr.ErrCodeParams, err.ErrCode())
}

func TestBuildCreateSharedPoolRequestKeepsRegionalDefaultForTopologyDrivenPdDeploymentMode(t *testing.T) {
	req := createResourcePoolRequestWithPdDeploymentMode(globalngv1.PdDeploymentMode_PD_DEPLOYMENT_MODE_UNSPECIFIED)

	sharedPoolReq, err := buildCreateSharedPoolRequest(req, 100, "cloud-identity", &clusterngv1beta.TopologySpec{})

	require.NoError(t, err)
	assert.Equal(
		t,
		clusterngv1beta.PDDeploymentMode_PD_DEPLOYMENT_MODE_UNSPECIFIED,
		sharedPoolReq.GetPdDeploymentMode(),
	)
}

func TestBuildCreateSharedPoolRequestRejectsMonolithicTopologyDrivenPdDeploymentMode(t *testing.T) {
	req := createResourcePoolRequestWithPdDeploymentMode(globalngv1.PdDeploymentMode_PD_DEPLOYMENT_MODE_MONOLITHIC)

	_, err := buildCreateSharedPoolRequest(req, 100, "cloud-identity", &clusterngv1beta.TopologySpec{})

	require.NotNil(t, err)
	assert.Equal(t, bizerr.ErrCodeParams, err.ErrCode())
	assert.Contains(t, err.Error(), "monolithic is not supported for topology-driven resource pools")
}

func createResourcePoolRequestWithPdDeploymentMode(
	mode globalngv1.PdDeploymentMode,
) *globalngv1.CreateResourcePoolRequest {
	return &globalngv1.CreateResourcePoolRequest{
		ResourcePool:     &globalngv1.ResourcePool{OwnerId: 42},
		PdDeploymentMode: mode,
		Demand: &globalngv1.CreateResourcePoolRequest_Demand{
			TikvData:    &globalngv1.CreateResourcePoolRequest_Storage{StorageType: globalngv1.ResourcePoolProfile_GP3},
			TikvRaftlog: &globalngv1.CreateResourcePoolRequest_Storage{StorageType: globalngv1.ResourcePoolProfile_GP3},
			TiflashCn:   &globalngv1.CreateResourcePoolRequest_Storage{StorageType: globalngv1.ResourcePoolProfile_GP3},
			TiflashWn:   &globalngv1.CreateResourcePoolRequest_Storage{StorageType: globalngv1.ResourcePoolProfile_GP3},
		},
	}
}
