package meta

import (
	"bytes"
	"context"
	"path/filepath"
	"testing"

	objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
	cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
	"github.com/stretchr/testify/require"
	"go.etcd.io/bbolt"
)

func TestPutDeleteIndexAttributes(t *testing.T) {
	db := New([]Option{
		WithPath(filepath.Join(t.TempDir(), "metabase")),
		WithPermissions(0o600),
		WithEpochState(epochState{}),
	}...)

	require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
	require.NoError(t, db.Init(context.Background()))
	defer func() { require.NoError(t, db.Close(context.Background())) }()

	cnr := cidtest.ID()
	obj1 := testutil.GenerateObjectWithCID(cnr)
	testutil.AddAttribute(obj1, "S3-Access-Box-CRDT-Name", "CRDT-Name")
	testutil.AddAttribute(obj1, objectSDK.AttributeFilePath, "/path/to/object")

	var putPrm PutPrm
	putPrm.SetObject(obj1)

	_, err := db.Put(context.Background(), putPrm)
	require.NoError(t, err)

	require.NoError(t, db.boltDB.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(attributeBucketName(cnr, "S3-Access-Box-CRDT-Name", make([]byte, bucketKeySize)))
		require.Nil(t, b)
		b = tx.Bucket(attributeBucketName(cnr, objectSDK.AttributeFilePath, make([]byte, bucketKeySize)))
		require.Nil(t, b)
		return nil
	}))

	obj2 := testutil.GenerateObjectWithCID(cnr)
	testutil.AddAttribute(obj2, "S3-Access-Box-CRDT-Name", "CRDT-Name")
	testutil.AddAttribute(obj2, objectSDK.AttributeFilePath, "/path/to/object")

	putPrm.SetObject(obj2)
	putPrm.SetIndexAttributes(true)

	_, err = db.Put(context.Background(), putPrm)
	require.NoError(t, err)

	objKey := objectKey(objectCore.AddressOf(obj2).Object(), make([]byte, objectKeySize))
	require.NoError(t, db.boltDB.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(attributeBucketName(cnr, "S3-Access-Box-CRDT-Name", make([]byte, bucketKeySize)))
		require.NotNil(t, b)
		b = b.Bucket([]byte("CRDT-Name"))
		require.NotNil(t, b)
		require.True(t, bytes.Equal(zeroValue, b.Get(objKey)))
		b = tx.Bucket(attributeBucketName(cnr, objectSDK.AttributeFilePath, make([]byte, bucketKeySize)))
		require.NotNil(t, b)
		b = b.Bucket([]byte("/path/to/object"))
		require.NotNil(t, b)
		require.True(t, bytes.Equal(zeroValue, b.Get(objKey)))
		return nil
	}))

	var dPrm DeletePrm
	dPrm.SetAddresses(objectCore.AddressOf(obj1), objectCore.AddressOf(obj2))
	_, err = db.Delete(context.Background(), dPrm)
	require.NoError(t, err)

	require.NoError(t, db.boltDB.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(attributeBucketName(cnr, "S3-Access-Box-CRDT-Name", make([]byte, bucketKeySize)))
		require.Nil(t, b)
		b = tx.Bucket(attributeBucketName(cnr, objectSDK.AttributeFilePath, make([]byte, bucketKeySize)))
		require.Nil(t, b)
		return nil
	}))
}