package transformer

import (
	"context"
	"crypto/rand"
	"math"
	"testing"

	cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
	"github.com/stretchr/testify/require"
)

func TestTransformerSizeHintCorrectness(t *testing.T) {
	const (
		maxSize     = 100
		payloadSize = maxSize*2 + maxSize/2
	)

	pk, err := keys.NewPrivateKey()
	require.NoError(t, err)

	p := Params{
		Key:                    &pk.PrivateKey,
		NetworkState:           dummyEpochSource(123),
		MaxSize:                maxSize,
		WithoutHomomorphicHash: true,
	}

	cnr := cidtest.ID()
	hdr := newObject(cnr)

	var owner user.ID
	user.IDFromKey(&owner, pk.PrivateKey.PublicKey)
	hdr.SetOwnerID(owner)

	expected := make([]byte, payloadSize)
	_, _ = rand.Read(expected)

	t.Run("default", func(t *testing.T) {
		p.SizeHint = 0
		testPayloadEqual(t, p, hdr, expected)
	})
	t.Run("size hint is perfect", func(t *testing.T) {
		p.SizeHint = payloadSize
		testPayloadEqual(t, p, hdr, expected)
	})
	t.Run("size hint < payload size", func(t *testing.T) {
		p.SizeHint = payloadSize / 2
		testPayloadEqual(t, p, hdr, expected)
	})
	t.Run("size hint > payload size", func(t *testing.T) {
		p.SizeHint = math.MaxUint64
		testPayloadEqual(t, p, hdr, expected)
	})
}

func testPayloadEqual(t *testing.T, p Params, hdr *objectSDK.Object, expected []byte) {
	tt := new(testTarget)

	p.NextTargetInit = func() ObjectWriter { return tt }
	target := NewPayloadSizeLimiter(p)

	writeObject(t, context.Background(), target, hdr, expected)
	var actual []byte
	for i := range tt.objects {
		actual = append(actual, tt.objects[i].Payload()...)
	}
	require.Equal(t, expected, actual)
}