package engine

import (
	"context"
	"testing"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
	"git.frostfs.info/TrueCloudLab/hrw"
	"github.com/stretchr/testify/require"
)

func TestRemoveShard(t *testing.T) {
	const numOfShards = 6

	te := testNewEngine(t).setShardsNum(t, numOfShards)
	e, ids := te.engine, te.shardIDs
	defer func() { require.NoError(t, e.Close(context.Background())) }()

	require.Equal(t, numOfShards, len(e.shardPools))
	require.Equal(t, numOfShards, len(e.shards))

	removedNum := numOfShards / 2

	mSh := make(map[string]bool, numOfShards)
	for i, id := range ids {
		if i == removedNum {
			break
		}

		mSh[id.String()] = true
	}

	for id, remove := range mSh {
		if remove {
			e.removeShards(id)
		}
	}

	require.Equal(t, numOfShards-removedNum, len(e.shardPools))
	require.Equal(t, numOfShards-removedNum, len(e.shards))

	for id, removed := range mSh {
		_, ok := e.shards[id]
		require.True(t, ok != removed)
	}
}

func TestDisableShards(t *testing.T) {
	t.Parallel()

	const numOfShards = 2

	te := testNewEngine(t).setShardsNum(t, numOfShards)
	e, ids := te.engine, te.shardIDs
	defer func() { require.NoError(t, e.Close(context.Background())) }()

	require.ErrorAs(t, e.DetachShards(ids), new(logicerr.Logical))
	require.ErrorAs(t, e.DetachShards(nil), new(logicerr.Logical))
	require.ErrorAs(t, e.DetachShards([]*shard.ID{}), new(logicerr.Logical))

	require.NoError(t, e.DetachShards([]*shard.ID{ids[0]}))

	require.Equal(t, 1, len(e.shards))
}

func TestSortShardsByWeight(t *testing.T) {
	t.Parallel()

	const numOfShards = 500

	var shards1 []hashedShard
	var weights1 []float64
	var shards2 []hashedShard
	for i := range numOfShards {
		shards1 = append(shards1, hashedShard{
			hash: uint64(i),
		})
		weights1 = append(weights1, 0)
		shards2 = append(shards2, hashedShard{
			hash: uint64(i),
		})
	}

	hrw.SortHasherSliceByWeightValue(shards1, weights1, 0)
	hrw.SortHasherSliceByValue(shards2, 0)

	require.Equal(t, shards1, shards2)
}