package api

import (
	"context"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	apiv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/ticdc-service/v1"
	"github.com/tidbcloud/ticdc-service/pkg/clusterproxy/client/mocks"
)

const (
	testURI = "test-uri"
	taskID  = "test-task-id"
)

func TestCreateChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()
	req := &apiv1.ChangefeedConfig{}

	mockClient.EXPECT().Request(gomock.Any(), "POST", "/ticdc/cr/api/v2/changefeeds", req, gomock.Any()).DoAndReturn(
		func(ctx context.Context, method string, relative string, body interface{}, dest interface{}) error {
			dest.(*apiv1.Changefeed).SinkUri = testURI
			return nil
		}).Times(1)
	resp, err := changefeedAPI.CreateChangefeedV2(ctx, "cr", req)
	assert.NoError(t, err)
	assert.Equal(t, testURI, resp.SinkUri)
}

func TestUpdateChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()
	req := &apiv1.ChangefeedConfig{}

	mockClient.EXPECT().Request(gomock.Any(), "PUT", "/ticdc/cr/api/v2/changefeeds/"+taskID, req, gomock.Any()).DoAndReturn(
		func(ctx context.Context, method string, relative string, body interface{}, dest interface{}) error {
			dest.(*apiv1.Changefeed).SinkUri = testURI
			return nil
		},
	).Times(1)

	resp, err := changefeedAPI.UpdateChangefeedV2(ctx, "cr", taskID, req)
	assert.NoError(t, err)
	assert.Equal(t, testURI, resp.SinkUri)
}

func TestGetChangefeedListV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()

	mockClient.EXPECT().Request(gomock.Any(), "GET", "/ticdc/cr/api/v2/changefeeds?state=all", nil, gomock.Any()).DoAndReturn(
		func(ctx context.Context, method string, relative string, body interface{}, dest interface{}) error {
			dest.(*apiv1.ListChangefeedsResponse).Items = []*apiv1.ChangefeedCommonInfo{{Id: taskID}}
			return nil
		},
	).Times(1)

	resp, err := changefeedAPI.GetChangefeedListV2(ctx, "cr")
	assert.NoError(t, err)
	assert.Equal(t, 1, len(resp.Items))
	assert.Equal(t, taskID, resp.Items[0].Id)
}

func TestPauseChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()

	mockClient.EXPECT().Request(gomock.Any(), "POST", "/ticdc/cr/api/v2/changefeeds/"+taskID+"/pause", nil, nil).Return(nil).Times(1)

	err := changefeedAPI.PauseChangefeedV2(ctx, "cr", taskID)
	assert.NoError(t, err)
}

func TestResumeChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()
	req := &apiv1.ResumeChangefeedConfig{}

	mockClient.EXPECT().Request(gomock.Any(), "POST", "/ticdc/cr/api/v2/changefeeds/"+taskID+"/resume", req, nil).Return(nil).Times(1)

	err := changefeedAPI.ResumeChangefeedV2(ctx, "cr", taskID, req)
	assert.NoError(t, err)
}

func TestDeleteChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()

	mockClient.EXPECT().Request(gomock.Any(), "DELETE", "/ticdc/cr/api/v2/changefeeds/"+taskID, nil, nil).Return(nil).Times(1)

	err := changefeedAPI.DeleteChangefeedV2(ctx, "cr", taskID)
	assert.NoError(t, err)
}

func TestGetChangefeedV2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()

	mockClient.EXPECT().Request(gomock.Any(), "GET", "/ticdc/cr/api/v2/changefeeds/"+taskID, nil, gomock.Any()).DoAndReturn(
		func(ctx context.Context, method string, relative string, body interface{}, dest interface{}) error {
			dest.(*apiv1.Changefeed).SinkUri = testURI
			return nil
		},
	).Times(1)

	resp, err := changefeedAPI.GetChangefeedV2(ctx, "cr", taskID)
	assert.NoError(t, err)
	assert.Equal(t, testURI, resp.SinkUri)
}

func TestTestConnection(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockClient := mocks.NewMockClient(ctrl)
	changefeedAPI := NewChangefeedAPIV2(mockClient)

	ctx := context.Background()
	req := &ConnectionModel{}

	mockClient.EXPECT().Request(gomock.Any(), "POST", "/test_connection", req, nil).Return(nil).Times(1)

	err := changefeedAPI.TestConnection(ctx, req)
	assert.NoError(t, err)
}
