package processor

import (
	"bytes"
	"fmt"
	"io/fs"
	"os"
	"testing"

	"github.com/aws/aws-sdk-go-v2/aws"
	s3api "github.com/aws/aws-sdk-go-v2/service/s3"
	"github.com/aws/aws-sdk-go-v2/service/s3/types"
	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	mock_data_processor "github.com/tidbcloud/observability/data-collector/test/mockdataprocessor"
)

func newMockS3Client(mock s3Client) S3Client {
	return S3Client{
		cli: mock,
	}
}

type CBuffer struct {
	*bytes.Buffer
}

func (c *CBuffer) Close() error {
	return nil
}

func TestDownloadFile(t *testing.T) {
	ctl := gomock.NewController(t)
	mocks3 := mock_data_processor.NewMocks3Client(ctl)
	s3 := newMockS3Client(mocks3)
	t.Run("success", func(t *testing.T) {
		mocks3.EXPECT().ListObjects(gomock.Any(), gomock.Any(), gomock.Any()).Return(&s3api.ListObjectsOutput{
			Contents: []types.Object{
				{
					Key: aws.String("test.csv"),
				},
			},
			Prefix: aws.String("test/data"),
		}, nil)
		buf := make([]byte, 1)
		tmp := CBuffer{bytes.NewBuffer(buf)}
		mocks3.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).Return(&s3api.GetObjectOutput{
			Body:          &tmp,
			ContentLength: 1,
		}, nil)
		objects, err := s3.DownloadFiles("test", "test/data")
		assert.NotEmpty(t, objects)
		assert.Equal(t, 1, len(objects))
		assert.NoError(t, err)
	})
	t.Run("list objects err", func(t *testing.T) {
		mocks3.EXPECT().ListObjects(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("err"))
		objects, err := s3.DownloadFiles("test", "test/data")
		assert.Nil(t, objects)
		assert.Error(t, err)
	})
	t.Run("success", func(t *testing.T) {
		mocks3.EXPECT().ListObjects(gomock.Any(), gomock.Any(), gomock.Any()).Return(&s3api.ListObjectsOutput{
			Contents: []types.Object{
				{
					Key: aws.String("test.csv"),
				},
			},
			Prefix: aws.String("test/data"),
		}, nil)

		mocks3.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("err"))
		objects, err := s3.DownloadFiles("test", "test/data")
		assert.Nil(t, objects)
		assert.Error(t, err)
	})

}

func TestUploadFile(t *testing.T) {
	ctl := gomock.NewController(t)
	mocks3 := mock_data_processor.NewMocks3Client(ctl)
	s3 := newMockS3Client(mocks3)
	t.Run("success", func(t *testing.T) {
		path := "test.txt"
		os.WriteFile(path, []byte("123"), fs.ModePerm)
		defer os.Remove(path)
		mocks3.EXPECT().PutObject(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil)
		err := s3.UploadFile("test.txt", "test", "test/data")
		assert.NoError(t, err)
	})
	t.Run("no file error", func(t *testing.T) {
		err := s3.UploadFile("fn", "test", "test/data")
		assert.Error(t, err)
	})

}
