package regionalapi

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

	"github.com/stretchr/testify/require"
	replay_v1 "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-server/v1"
	"github.com/tidbcloud/pkgv2/bizerr"
	global_commonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	tidb_mgmt_servicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
)

type replayRecordingRegionalClient struct {
	method string
	path   string
	region *Region
}

func (c *replayRecordingRegionalClient) Get(
	_ context.Context,
	region *Region,
	uriPath string,
	_ map[string]string,
	_ url.Values,
	_ interface{},
) bizerr.BizError {
	c.record(http.MethodGet, region, uriPath)
	return nil
}

func (c *replayRecordingRegionalClient) Post(
	_ context.Context,
	region *Region,
	uriPath string,
	_ map[string]string,
	_ url.Values,
	_, _ interface{},
) bizerr.BizError {
	c.record(http.MethodPost, region, uriPath)
	return nil
}

func (c *replayRecordingRegionalClient) Put(
	_ context.Context,
	region *Region,
	uriPath string,
	_ map[string]string,
	_, _ interface{},
) bizerr.BizError {
	c.record(http.MethodPut, region, uriPath)
	return nil
}

func (c *replayRecordingRegionalClient) Delete(
	_ context.Context,
	region *Region,
	uriPath string,
	_ map[string]string,
	_ url.Values,
) bizerr.BizError {
	c.record(http.MethodDelete, region, uriPath)
	return nil
}

func (c *replayRecordingRegionalClient) ListRegions(context.Context) ([]RegionInfo, bizerr.BizError) {
	return nil, nil
}

func (c *replayRecordingRegionalClient) record(method string, region *Region, uriPath string) {
	c.method = method
	c.region = region
	c.path = uriPath
}

func TestReplayClientUsesClusterServerPath(t *testing.T) {
	t.Parallel()
	ctx := context.Background()
	nextGenPremiumRegion := &Region{
		DeployType:  tidb_mgmt_servicev1.DeployType_DEPLOY_TYPE_NEXTGEN,
		ServicePlan: global_commonv1.ServicePlan_Premium,
	}
	tests := map[string]struct {
		region     *Region
		call       func(ReplayClient, *Region) bizerr.BizError
		wantMethod string
		wantPath   string
	}{
		"create premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.CreateReplay(ctx, region, &replay_v1.CreateReplayRequest{})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays",
		},
		"get premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.GetReplay(ctx, region, &replay_v1.GetReplayRequest{ReplayId: "replay-1"})
				return err
			},
			wantMethod: http.MethodGet,
			wantPath:   "/cluster-server/api/v1/replays/{replay_id}",
		},
		"update premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.UpdateReplay(ctx, region, &replay_v1.UpdateReplayRequest{
					Replay: &replay_v1.Replay{ReplayId: "replay-1"},
				})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays/{replay_id}",
		},
		"delete premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.DeleteReplay(ctx, region, &replay_v1.DeleteReplayRequest{ReplayId: "replay-1"})
				return err
			},
			wantMethod: http.MethodDelete,
			wantPath:   "/cluster-server/api/v1/replays/{replay_id}",
		},
		"start premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.StartReplay(ctx, region, &replay_v1.StartReplayRequest{ReplayId: "replay-1"})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays/{replay_id}:start",
		},
		"stop premium nextgen": {
			region: nextGenPremiumRegion,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.StopReplay(ctx, region, &replay_v1.StopReplayRequest{ReplayId: "replay-1"})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays/{replay_id}:stop",
		},
		"create nil region": {
			region: nil,
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.CreateReplay(ctx, region, &replay_v1.CreateReplayRequest{})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays",
		},
		"create dedicated": {
			region: &Region{
				DeployType: tidb_mgmt_servicev1.DeployType_DEPLOY_TYPE_DEDICATED,
			},
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.CreateReplay(ctx, region, &replay_v1.CreateReplayRequest{})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays",
		},
		"create nextgen non premium": {
			region: &Region{
				DeployType:  tidb_mgmt_servicev1.DeployType_DEPLOY_TYPE_NEXTGEN,
				ServicePlan: global_commonv1.ServicePlan_Starter,
			},
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.CreateReplay(ctx, region, &replay_v1.CreateReplayRequest{})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays",
		},
		"create unspecified": {
			region: &Region{
				DeployType:  tidb_mgmt_servicev1.DeployType_DEPLOY_TYPE_UNSPECIFIED,
				ServicePlan: global_commonv1.ServicePlan_SERVICE_PLAN_UNSPECIFIED,
			},
			call: func(client ReplayClient, region *Region) bizerr.BizError {
				_, err := client.CreateReplay(ctx, region, &replay_v1.CreateReplayRequest{})
				return err
			},
			wantMethod: http.MethodPost,
			wantPath:   "/cluster-server/api/v1/replays",
		},
	}

	for name, tc := range tests {
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			regionalCli := &replayRecordingRegionalClient{}
			err := tc.call(NewReplayClient(regionalCli), tc.region)
			require.NoError(t, err)
			require.Equal(t, tc.wantMethod, regionalCli.method)
			require.Equal(t, tc.wantPath, regionalCli.path)
			require.Equal(t, tc.region, regionalCli.region)
		})
	}
}
