package task

import (
	"fmt"
	"strconv"
	"sync"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/observability/data-collector/pkg/collector/sources"
	mock_sinks "github.com/tidbcloud/observability/data-collector/test/mocksinks"
	mock_sources "github.com/tidbcloud/observability/data-collector/test/mocksources"
)

type mockConfig struct {
}

func (mockConfig) GetType() string {
	return "mock types"
}
func (mockConfig) GetName() string {
	return "mock name"
}
func (mockConfig) GetVersion() string {
	return "mock versions"
}

func TestExcute(t *testing.T) {
	tasks := NewExcutor(nil)
	assert.NoError(t, tasks.Excute(0))
}

func TestInnerExcute(t *testing.T) {
	ctl := gomock.NewController(t)
	mocksinks := mock_sinks.NewMockSink(ctl)
	mocksources := mock_sources.NewMockSource(ctl)
	tasks := NewExcutor([]Task{
		NewTask(mocksources, mocksinks),
	})
	mocksources.EXPECT().GetConfig().Return(mockConfig{}).AnyTimes()
	//download checkpoint failed
	testerr := fmt.Errorf("test failed")
	mocksinks.EXPECT().DownloadFile(gomock.Any()).Return(nil, false, testerr)
	var wg sync.WaitGroup
	wg.Add(10)
	err := tasks.excute(&wg, tasks.tasks[0], 0)
	if assert.Error(t, err) {
		assert.Equal(t, testerr, err)
	}
	// result failed
	mocksinks.EXPECT().DownloadFile(gomock.Any()).Return(nil, false, nil)
	mocksources.EXPECT().Run(gomock.Any(), gomock.Any()).Return(nil, testerr)
	err = tasks.excute(&wg, tasks.tasks[0], 0)
	if assert.Error(t, err) {
		assert.Equal(t, testerr, err)
	}
	//upload failed
	mocksinks.EXPECT().DownloadFile(gomock.Any()).Return(nil, false, nil)
	mocksources.EXPECT().Run(gomock.Any(), gomock.Any()).Return([]sources.Result{
		{
			Path: "/mock/test",
			Body: []byte("test"),
		},
	}, nil)
	mocksinks.EXPECT().WriteToFile(gomock.Any(), gomock.Any()).Return(testerr)
	err = tasks.excute(&wg, tasks.tasks[0], 0)
	if assert.Error(t, err) {
		assert.Equal(t, testerr, err)
	}
	//upload checkpoint failed
	mocksinks.EXPECT().DownloadFile(gomock.Any()).Return(nil, false, nil)
	mocksources.EXPECT().Run(gomock.Any(), gomock.Any()).Return([]sources.Result{
		{
			Path: "/mock/test",
			Body: []byte("test"),
		},
	}, nil)
	mocksinks.EXPECT().WriteToFile(gomock.Any(), gomock.Any()).Return(nil)
	mocksinks.EXPECT().WriteToFile(gomock.Any(), gomock.Any()).Return(testerr)
	err = tasks.excute(&wg, tasks.tasks[0], 0)
	if assert.Error(t, err) {
		assert.Equal(t, testerr, err)
	}
	// success
	mocksinks.EXPECT().DownloadFile(gomock.Any()).Return([]byte(strconv.FormatInt(1678283417, 10)), true, nil)
	mocksources.EXPECT().Run(gomock.Any(), gomock.Any()).Return([]sources.Result{
		{
			Path: "/mock/test",
			Body: []byte("test"),
		},
	}, nil)
	mocksinks.EXPECT().WriteToFile(gomock.Any(), gomock.Any()).Return(nil)
	mocksinks.EXPECT().WriteToFile(gomock.Any(), gomock.Any()).Return(nil)
	assert.NoError(t, tasks.excute(&wg, tasks.tasks[0], 0))
}
