package engine

import (
	"context"
	"strconv"
	"testing"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
	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"
)

func BenchmarkTreeVsSearch(b *testing.B) {
	b.Run("10 objects", func(b *testing.B) {
		benchmarkTreeVsSearch(b, 10)
	})
	b.Run("100 objects", func(b *testing.B) {
		benchmarkTreeVsSearch(b, 100)
	})
	b.Run("1000 objects", func(b *testing.B) {
		benchmarkTreeVsSearch(b, 1000)
	})
}

func benchmarkTreeVsSearch(b *testing.B, objCount int) {
	te := newEngineWithErrorThreshold(b, "", 0)
	defer func() {
		require.NoError(b, te.ng.Close(context.Background()))
	}()

	cid := cidtest.ID()
	d := pilorama.CIDDescriptor{CID: cid, Position: 0, Size: 1}
	treeID := "someTree"

	for i := range objCount {
		obj := testutil.GenerateObjectWithCID(cid)
		testutil.AddAttribute(obj, pilorama.AttributeFilename, strconv.Itoa(i))
		err := Put(context.Background(), te.ng, obj, false)
		if err != nil {
			b.Fatal(err)
		}
		_, err = te.ng.TreeAddByPath(context.Background(), d, treeID, pilorama.AttributeFilename, nil,
			[]pilorama.KeyValue{{Key: pilorama.AttributeFilename, Value: []byte(strconv.Itoa(i))}})
		if err != nil {
			b.Fatal(err)
		}
	}

	b.Run("search", func(b *testing.B) {
		var prm SelectPrm
		prm.WithContainerID(cid, true)

		var fs objectSDK.SearchFilters
		fs.AddFilter(pilorama.AttributeFilename, strconv.Itoa(objCount/2), objectSDK.MatchStringEqual)
		prm.WithFilters(fs)

		for range b.N {
			res, err := te.ng.Select(context.Background(), prm)
			if err != nil {
				b.Fatal(err)
			}
			if count := len(res.addrList); count != 1 {
				b.Fatalf("expected 1 object, got %d", count)
			}
		}
	})
	b.Run("TreeGetByPath", func(b *testing.B) {
		for range b.N {
			nodes, err := te.ng.TreeGetByPath(context.Background(), cid, treeID, pilorama.AttributeFilename, []string{strconv.Itoa(objCount / 2)}, true)
			if err != nil {
				b.Fatal(err)
			}
			if count := len(nodes); count != 1 {
				b.Fatalf("expected 1 object, got %d", count)
			}
		}
	})
}