package tidbtools

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/dataflow-service/idl/pbgen/proto/dataflow"
	"github.com/tidbcloud/devops/pkg/infra/clients/coresvccli"
	toolsapi "github.com/tidbcloud/devops/pkg/service/tidbtools/api"
	commonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"go.uber.org/mock/gomock"
)

func TestBackupSettingRoutesAreClusterTypeSpecific(t *testing.T) {
	gin.SetMode(gin.TestMode)
	tests := []struct {
		name      string
		handler   func(*TidbToolsController, *gin.Context)
		cluster   *mgmtv1.Cluster
		expectSvc func(*toolsapi.MockTidbToolsServiceAPI)
		wantCode  int
	}{
		{
			name:    "Dedicated endpoint accepts Dedicated",
			handler: (*TidbToolsController).GetBackupSetting,
			cluster: &mgmtv1.Cluster{ClusterId: 42, DeployType: mgmtv1.DeployType_DEPLOY_TYPE_DEDICATED},
			expectSvc: func(svc *toolsapi.MockTidbToolsServiceAPI) {
				svc.EXPECT().GetBackupSetting(gomock.Any(), uint64(0), uint64(0), uint64(42)).Return(&dataflow.QueryBackupSettingResp{}, nil)
			},
			wantCode: http.StatusOK,
		},
		{
			name:     "Dedicated endpoint rejects Premium",
			handler:  (*TidbToolsController).GetBackupSetting,
			cluster:  nextGenCluster(commonv1.ServicePlan_Premium),
			wantCode: http.StatusNotImplemented,
		},
		{
			name:    "NextGen endpoint accepts Premium",
			handler: (*TidbToolsController).GetNextGenBackupSetting,
			cluster: nextGenCluster(commonv1.ServicePlan_Premium),
			expectSvc: func(svc *toolsapi.MockTidbToolsServiceAPI) {
				svc.EXPECT().GetPremiumBackupSetting(gomock.Any(), uint64(0), uint64(0), uint64(42)).Return(nil, nil, nil)
			},
			wantCode: http.StatusOK,
		},
		{
			name:    "NextGen endpoint accepts Essential v2",
			handler: (*TidbToolsController).GetNextGenBackupSetting,
			cluster: nextGenCluster(commonv1.ServicePlan_Essential_V2),
			expectSvc: func(svc *toolsapi.MockTidbToolsServiceAPI) {
				svc.EXPECT().GetPremiumBackupSetting(gomock.Any(), uint64(0), uint64(0), uint64(42)).Return(nil, nil, nil)
			},
			wantCode: http.StatusOK,
		},
		{
			name:     "NextGen endpoint rejects Dedicated",
			handler:  (*TidbToolsController).GetNextGenBackupSetting,
			cluster:  &mgmtv1.Cluster{ClusterId: 42, DeployType: mgmtv1.DeployType_DEPLOY_TYPE_DEDICATED},
			wantCode: http.StatusNotImplemented,
		},
		{
			name:     "NextGen endpoint rejects unsupported plan",
			handler:  (*TidbToolsController).GetNextGenBackupSetting,
			cluster:  nextGenCluster(commonv1.ServicePlan_BYOC),
			wantCode: http.StatusNotImplemented,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mockCtrl := gomock.NewController(t)
			clusterClient := coresvccli.NewMockClusterServiceClient(mockCtrl)
			clusterClient.EXPECT().ListClusters(gomock.Any(), gomock.Any()).Return(&mgmtv1.ListClustersResponse{Clusters: []*mgmtv1.Cluster{tt.cluster}}, nil)
			svc := toolsapi.NewMockTidbToolsServiceAPI(mockCtrl)
			if tt.expectSvc != nil {
				tt.expectSvc(svc)
			}
			controller := &TidbToolsController{
				svc:        svc,
				coreSvcCli: &coresvccli.CoreSvcCli{Mgmt: &coresvccli.MgmtService{Cluster: clusterClient}},
			}
			recorder := httptest.NewRecorder()
			ctx, _ := gin.CreateTestContext(recorder)
			ctx.Params = gin.Params{{Key: "cluster_id", Value: "42"}}
			ctx.Request = httptest.NewRequest(http.MethodGet, "/42/tidbtools/backup-setting", nil)

			tt.handler(controller, ctx)
			if recorder.Code != tt.wantCode {
				t.Fatalf("status = %d, want %d: %s", recorder.Code, tt.wantCode, recorder.Body.String())
			}
		})
	}
}

func nextGenCluster(servicePlan commonv1.ServicePlan) *mgmtv1.Cluster {
	return &mgmtv1.Cluster{
		ClusterId:   42,
		DeployType:  mgmtv1.DeployType_DEPLOY_TYPE_NEXTGEN,
		ClusterInfo: &mgmtv1.Cluster_NextGenCluster{NextGenCluster: &globalngv1.Cluster{ServicePlan: servicePlan}},
	}
}
