package meta_test

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

	objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
	meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
	cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
	"github.com/stretchr/testify/require"
)

type epochState struct{ e uint64 }

func (s epochState) CurrentEpoch() uint64 {
	if s.e != 0 {
		return s.e
	}

	return 0
}

// saves "big" object in DB.
func putBig(db *meta.DB, obj *objectSDK.Object) error {
	return metaPut(db, obj, nil)
}

func testSelect(t *testing.T, db *meta.DB, cnr cid.ID, fs objectSDK.SearchFilters, exp ...oid.Address) {
	res, err := metaSelect(db, cnr, fs)
	require.NoError(t, err)
	require.Len(t, res, len(exp))

	for i := range exp {
		require.Contains(t, res, exp[i])
	}
}

func newDB(t testing.TB, opts ...meta.Option) *meta.DB {
	bdb := meta.New(
		append([]meta.Option{
			meta.WithPath(filepath.Join(t.TempDir(), "metabase")),
			meta.WithPermissions(0o600),
			meta.WithEpochState(epochState{}),
		}, opts...)...,
	)

	require.NoError(t, bdb.Open(context.Background(), mode.ReadWrite))
	require.NoError(t, bdb.Init())

	return bdb
}

func checkExpiredObjects(t *testing.T, db *meta.DB, f func(exp, nonExp *objectSDK.Object)) {
	expObj := testutil.GenerateObject()
	setExpiration(expObj, currEpoch-1)

	require.NoError(t, metaPut(db, expObj, nil))

	nonExpObj := testutil.GenerateObject()
	setExpiration(nonExpObj, currEpoch)

	require.NoError(t, metaPut(db, nonExpObj, nil))

	f(expObj, nonExpObj)
}

func setExpiration(o *objectSDK.Object, epoch uint64) {
	var attr objectSDK.Attribute

	attr.SetKey(objectV2.SysAttributeExpEpoch)
	attr.SetValue(strconv.FormatUint(epoch, 10))

	o.SetAttributes(append(o.Attributes(), attr)...)
}