package clusteragent

import (
	"context"
	"net/http"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	cspb "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/ticdc-service-ng/pkg/util"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/tidbcloud/ticdc-service-ng/pkg/regionalservice"
	regionalMock "github.com/tidbcloud/ticdc-service-ng/pkg/regionalservice/mocks"
)

func TestModelGetClient_ErrorMapping(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*regionalMock.MockClient)
		wantCode codes.Code
	}{
		{
			name: "tidbGroup http 404 maps to NotFound",
			setup: func(m *regionalMock.MockClient) {
				m.EXPECT().GetOneTiDBGroupByClusterID(gomock.Any(), "cluster-1").
					Return(nil, &util.StatusError{StatusCode: http.StatusNotFound, Status: "Not Found", Body: "Not Found"})
			},
			wantCode: codes.NotFound,
		},
		{
			name: "tidbGroup semantic not found maps to NotFound",
			setup: func(m *regionalMock.MockClient) {
				m.EXPECT().GetOneTiDBGroupByClusterID(gomock.Any(), "cluster-1").
					Return(nil, &regionalservice.NotFoundError{Resource: "tidb group", ID: "cluster-1"})
			},
			wantCode: codes.NotFound,
		},
		{
			name: "dataplane http 404 maps to NotFound",
			setup: func(m *regionalMock.MockClient) {
				m.EXPECT().GetOneTiDBGroupByClusterID(gomock.Any(), "cluster-1").
					Return(&cspb.TiDBGroup{DataplaneName: "dp-1", SharedPoolId: "123"}, nil)
				m.EXPECT().GetDataPlaneByID(gomock.Any(), "dp-1").
					Return(nil, &util.StatusError{StatusCode: http.StatusNotFound, Status: "Not Found", Body: "Not Found"})
			},
			wantCode: codes.NotFound,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()

			regionalCli := regionalMock.NewMockClient(ctrl)
			tt.setup(regionalCli)

			model := NewModel(regionalCli)
			_, err := model.GetClient(context.Background(), "cluster-1", 1)
			require.Error(t, err)

			st, ok := status.FromError(err)
			require.True(t, ok)
			assert.Equal(t, tt.wantCode, st.Code())
		})
	}
}
