package object

import (
	"testing"

	v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
	oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
	"github.com/stretchr/testify/require"
)

func TestPatch(t *testing.T) {
	t.Run("to v2", func(t *testing.T) {
		t.Run("only attributes", func(t *testing.T) {
			var p Patch

			var attr1, attr2 Attribute
			attr1.SetKey("key1")
			attr1.SetValue("val1")
			attr2.SetKey("key2")
			attr2.SetValue("val2")

			p.Address = oidtest.Address()
			p.NewAttributes = []Attribute{attr1, attr2}
			p.ReplaceAttributes = true

			v2patch := p.ToV2()

			addr := new(oid.Address)
			require.NotNil(t, v2patch.GetAddress())
			addr.ReadFromV2(*v2patch.GetAddress())
			require.True(t, p.Address.Equals(*addr))

			require.Equal(t, p.ReplaceAttributes, v2patch.GetReplaceAttributes())

			require.Nil(t, v2patch.GetPatch())

			require.Len(t, v2patch.GetNewAttributes(), 2)
			require.Equal(t, attr1.Key(), v2patch.GetNewAttributes()[0].GetKey())
			require.Equal(t, attr2.Key(), v2patch.GetNewAttributes()[1].GetKey())
			require.Equal(t, attr1.Value(), v2patch.GetNewAttributes()[0].GetValue())
			require.Equal(t, attr2.Value(), v2patch.GetNewAttributes()[1].GetValue())
		})

		t.Run("with payload patch", func(t *testing.T) {
			var p Patch

			var attr1, attr2 Attribute
			attr1.SetKey("key1")
			attr1.SetValue("val1")
			attr2.SetKey("key2")
			attr2.SetValue("val2")

			p.Address = oidtest.Address()
			p.NewAttributes = []Attribute{attr1, attr2}
			p.ReplaceAttributes = true

			rng := &Range{}
			rng.SetOffset(100)
			rng.SetLength(10)
			p.PayloadPatch = &PayloadPatch{
				Range: rng,
				Chunk: []byte("payload_patch_chunk"),
			}

			v2patch := p.ToV2()

			addr := new(oid.Address)
			require.NotNil(t, v2patch.GetAddress())
			addr.ReadFromV2(*v2patch.GetAddress())
			require.True(t, p.Address.Equals(*addr))

			require.Equal(t, p.ReplaceAttributes, v2patch.GetReplaceAttributes())

			require.Len(t, v2patch.GetNewAttributes(), 2)
			require.Equal(t, attr1.Key(), v2patch.GetNewAttributes()[0].GetKey())
			require.Equal(t, attr2.Key(), v2patch.GetNewAttributes()[1].GetKey())
			require.Equal(t, attr1.Value(), v2patch.GetNewAttributes()[0].GetValue())
			require.Equal(t, attr2.Value(), v2patch.GetNewAttributes()[1].GetValue())

			require.NotNil(t, v2patch.GetPatch())
			require.NotNil(t, v2patch.GetPatch().Range)
			require.Equal(t, uint64(100), v2patch.GetPatch().Range.GetOffset())
			require.Equal(t, uint64(10), v2patch.GetPatch().Range.GetLength())
			require.Equal(t, []byte("payload_patch_chunk"), v2patch.GetPatch().Chunk)
		})

	})

	t.Run("from v2", func(t *testing.T) {
		t.Run("only attributes", func(t *testing.T) {
			v2patch := new(v2object.PatchRequestBody)

			address := oidtest.Address()
			v2addr := new(refs.Address)
			address.WriteToV2(v2addr)
			v2patch.SetAddress(v2addr)

			var attr1, attr2 Attribute
			attr1.SetKey("key1")
			attr1.SetValue("val1")
			attr2.SetKey("key2")
			attr2.SetValue("val2")

			v2patch.SetNewAttributes([]v2object.Attribute{
				*attr1.ToV2(), *attr2.ToV2(),
			})
			v2patch.SetReplaceAttributes(true)

			var p Patch
			p.FromV2(v2patch)

			require.Equal(t, address, p.Address)
			require.Equal(t, []Attribute{attr1, attr2}, p.NewAttributes)
			require.Equal(t, true, p.ReplaceAttributes)
			require.Nil(t, p.PayloadPatch)
		})

		t.Run("with payload patch", func(t *testing.T) {
			v2patchReqBody := new(v2object.PatchRequestBody)

			address := oidtest.Address()
			v2addr := new(refs.Address)
			address.WriteToV2(v2addr)
			v2patchReqBody.SetAddress(v2addr)

			var attr1, attr2 Attribute
			attr1.SetKey("key1")
			attr1.SetValue("val1")
			attr2.SetKey("key2")
			attr2.SetValue("val2")

			v2patchReqBody.SetNewAttributes([]v2object.Attribute{
				*attr1.ToV2(), *attr2.ToV2(),
			})
			v2patchReqBody.SetReplaceAttributes(true)

			v2Rng := &v2object.Range{}
			v2Rng.SetOffset(13)
			v2Rng.SetLength(10)
			v2Patch := &v2object.PatchRequestBodyPatch{
				Range: v2Rng,
				Chunk: []byte("payload_patch_chunk"),
			}
			v2patchReqBody.SetPatch(v2Patch)

			var p Patch
			p.FromV2(v2patchReqBody)

			require.Equal(t, address, p.Address)
			require.Equal(t, []Attribute{attr1, attr2}, p.NewAttributes)
			require.Equal(t, true, p.ReplaceAttributes)
			require.NotNil(t, p.PayloadPatch)
			require.NotNil(t, p.PayloadPatch.Range)
			require.Equal(t, uint64(13), p.PayloadPatch.Range.GetOffset())
			require.Equal(t, uint64(10), p.PayloadPatch.Range.GetLength())
			require.Equal(t, []byte("payload_patch_chunk"), p.PayloadPatch.Chunk)
		})
	})
}