package objectstorage

import (
	"bytes"
	"context"
	"io"
	"testing"

	aliyunoss "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/stretchr/testify/require"
)

type fakeOSSClient struct {
	putRequest    *aliyunoss.PutObjectRequest
	getRequest    *aliyunoss.GetObjectRequest
	deleteRequest *aliyunoss.DeleteObjectRequest
	payload       []byte
	getErr        error
}

func (fake *fakeOSSClient) PutObject(_ context.Context, request *aliyunoss.PutObjectRequest, _ ...func(*aliyunoss.Options)) (*aliyunoss.PutObjectResult, error) {
	fake.putRequest = request
	return &aliyunoss.PutObjectResult{}, nil
}

func (fake *fakeOSSClient) GetObject(_ context.Context, request *aliyunoss.GetObjectRequest, _ ...func(*aliyunoss.Options)) (*aliyunoss.GetObjectResult, error) {
	fake.getRequest = request
	if fake.getErr != nil {
		return nil, fake.getErr
	}
	return &aliyunoss.GetObjectResult{Body: io.NopCloser(bytes.NewReader(fake.payload))}, nil
}

func (fake *fakeOSSClient) DeleteObject(_ context.Context, request *aliyunoss.DeleteObjectRequest, _ ...func(*aliyunoss.Options)) (*aliyunoss.DeleteObjectResult, error) {
	fake.deleteRequest = request
	return &aliyunoss.DeleteObjectResult{}, nil
}

func TestOSSStoragePrefixesObjectKeys(t *testing.T) {
	t.Parallel()

	client := &fakeOSSClient{}
	storage := newOSSStorage("agentteam-static", "agentteam/objects", client)

	require.NoError(t, storage.Put(context.Background(), "attachments/wsp-1/att-1", "image/png", []byte("png")))
	require.NotNil(t, client.putRequest)
	require.Equal(t, "agentteam-static", aliyunoss.ToString(client.putRequest.Bucket))
	require.Equal(t, "agentteam/objects/attachments/wsp-1/att-1", aliyunoss.ToString(client.putRequest.Key))
	require.Equal(t, "image/png", aliyunoss.ToString(client.putRequest.ContentType))
	require.Equal(t, int64(3), aliyunoss.ToInt64(client.putRequest.ContentLength))
}

func TestOSSStorageReadsAndDeletesWithPrefix(t *testing.T) {
	t.Parallel()

	client := &fakeOSSClient{payload: []byte("hello")}
	storage := newOSSStorage("agentteam-static", "agentteam/objects", client)

	payload, err := storage.Get(context.Background(), "avatars/wsp-1/avt-1")
	require.NoError(t, err)
	require.Equal(t, []byte("hello"), payload)
	require.NotNil(t, client.getRequest)
	require.Equal(t, "agentteam/objects/avatars/wsp-1/avt-1", aliyunoss.ToString(client.getRequest.Key))

	require.NoError(t, storage.Delete(context.Background(), "avatars/wsp-1/avt-1"))
	require.NotNil(t, client.deleteRequest)
	require.Equal(t, "agentteam/objects/avatars/wsp-1/avt-1", aliyunoss.ToString(client.deleteRequest.Key))
}

func TestMapOSSReadErrorMapsNotFound(t *testing.T) {
	t.Parallel()

	err := mapOSSReadError("avatars/wsp-1/avt-1", &aliyunoss.ServiceError{StatusCode: 404, Code: "NoSuchKey"})
	require.ErrorIs(t, err, ErrObjectNotFound)
}
