package attachment

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/objectstorage"
)

type attachmentDownloadRowStub struct {
	payload []byte
	err     error
}

func (row *attachmentDownloadRowStub) Scan(dest ...any) error {
	if row.err != nil {
		return row.err
	}
	blob := dest[0].(*[]byte)
	*blob = append([]byte(nil), row.payload...)
	return nil
}

type avatarDownloadRowStub struct {
	filename      string
	contentType   string
	storageDriver string
	objectKey     string
	blob          []byte
	err           error
}

func (row *avatarDownloadRowStub) Scan(dest ...any) error {
	if row.err != nil {
		return row.err
	}
	*dest[0].(*string) = row.filename
	*dest[1].(*string) = row.contentType
	*dest[2].(*string) = row.storageDriver
	*dest[3].(*string) = row.objectKey
	*dest[4].(*[]byte) = append([]byte(nil), row.blob...)
	return nil
}

type attachmentDownloadTxStub struct {
	row        coredb.Row
	lastQuery  string
	lastArgs   []any
	queryCalls int
}

func (tx *attachmentDownloadTxStub) QueryRow(_ context.Context, query string, args ...any) coredb.Row {
	tx.lastQuery = query
	tx.lastArgs = append([]any(nil), args...)
	tx.queryCalls++
	return tx.row
}

func (*attachmentDownloadTxStub) Query(context.Context, string, ...any) (coredb.Rows, error) {
	panic("unexpected Query call")
}

func (*attachmentDownloadTxStub) Exec(context.Context, string, ...any) (coredb.Result, error) {
	panic("unexpected Exec call")
}

func (*attachmentDownloadTxStub) Commit(context.Context) error {
	panic("unexpected Commit call")
}

func (*attachmentDownloadTxStub) Rollback(context.Context) error {
	panic("unexpected Rollback call")
}

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

	tx := &attachmentDownloadTxStub{
		row: &attachmentDownloadRowStub{},
	}
	store := TxStore{
		tx: tx,
		sharedStore: sharedStore{
			mediaObjectStorage: &fakeMediaStorage{
				driver:  objectstorage.DriverOSS,
				getBlob: []byte("oss-image"),
			},
			mediaPublicBaseURL: "https://media.agentteam.pingcap.com",
			mediaObjectPrefix:  "agentteam/objects",
		},
	}

	download, err := store.loadAttachmentDownloadBlob(context.Background(), attachmentDownloadRecord{
		ID: "att_1",
		Download: AttachmentDownload{
			Filename:    "image.png",
			ContentType: "image/png",
		},
		StorageDriver: objectstorage.DriverOSS,
		ObjectKey:     "attachments/wsp_1/att_1",
	})

	require.NoError(t, err)
	require.Equal(t, []byte("oss-image"), download.Blob)
	require.Equal(
		t,
		"https://media.agentteam.pingcap.com/agentteam/objects/attachments/wsp_1/att_1",
		download.PublicURL,
	)
	require.Equal(t, 1, tx.queryCalls)
	require.Contains(t, tx.lastQuery, "SELECT payload")
	require.Equal(t, []any{"att_1"}, tx.lastArgs)
}

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

	tx := &attachmentDownloadTxStub{
		row: &avatarDownloadRowStub{
			filename:      "avatar.svg",
			contentType:   "image/svg+xml",
			storageDriver: objectstorage.DriverOSS,
			objectKey:     "avatars/wsp_1/avt_1",
		},
	}
	store := TxStore{
		tx: tx,
		sharedStore: sharedStore{
			mediaObjectStorage: &fakeMediaStorage{
				driver:  objectstorage.DriverOSS,
				getBlob: []byte("<svg/>"),
			},
			mediaPublicBaseURL: "https://media.agentteam.pingcap.com",
			mediaObjectPrefix:  "agentteam/objects",
		},
	}

	download, err := store.LoadAvatar(context.Background(), "avt_1")

	require.NoError(t, err)
	require.Equal(t, "avatar.svg", download.Filename)
	require.Equal(t, "image/svg+xml", download.ContentType)
	require.Equal(t, []byte("<svg/>"), download.Blob)
	require.Empty(t, download.PublicURL)
	require.Equal(t, 1, tx.queryCalls)
	require.Contains(t, tx.lastQuery, "FROM avatars")
	require.Equal(t, []any{"avt_1"}, tx.lastArgs)
}
