package dataplane

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type fakeDataPlaneClient struct {
	dplanemgrv1.DataPlaneServiceClient
	resp *dplanemgrv1.DataPlane
	err  error
	got  *dplanemgrv1.GetDataPlaneRequest
}

func (f *fakeDataPlaneClient) GetDataPlane(_ context.Context, req *dplanemgrv1.GetDataPlaneRequest, _ ...grpc.CallOption) (*dplanemgrv1.DataPlane, error) {
	f.got = req
	return f.resp, f.err
}

func TestRequireDataplaneCapability(t *testing.T) {
	tests := []struct {
		name       string
		resp       *dplanemgrv1.DataPlane
		err        error
		wantCode   codes.Code
		wantPassed bool
	}{
		{
			name:       "advertised",
			resp:       &dplanemgrv1.DataPlane{Capabilities: []string{"other", CapabilityLoadBalancerMultiPort}},
			wantPassed: true,
		},
		{
			name:     "missing",
			resp:     &dplanemgrv1.DataPlane{Capabilities: []string{"other"}},
			wantCode: codes.FailedPrecondition,
		},
		{
			name:     "empty list",
			resp:     &dplanemgrv1.DataPlane{},
			wantCode: codes.FailedPrecondition,
		},
		{
			name: "rpc error propagates",
			err:  errors.New("transport error"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cli := &fakeDataPlaneClient{resp: tt.resp, err: tt.err}
			got := RequireDataplaneCapability(context.Background(), cli, "dp-1", CapabilityLoadBalancerMultiPort)

			require.NotNil(t, cli.got)
			assert.Equal(t, "dp-1", cli.got.GetDataPlaneId())

			switch {
			case tt.wantPassed:
				require.NoError(t, got)
			case tt.err != nil:
				require.ErrorIs(t, got, tt.err)
			default:
				st, ok := status.FromError(got)
				require.True(t, ok, "expected gRPC status error, got %T: %v", got, got)
				assert.Equal(t, tt.wantCode, st.Code())
			}
		})
	}
}
