package ape

import (
	"slices"
	"testing"

	cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
	oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
	sessionSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
	nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
	"github.com/stretchr/testify/require"
)

func TestIsVerbCompatible(t *testing.T) {
	table := map[string][]sessionSDK.ObjectVerb{
		nativeschema.MethodPutObject:    {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete, sessionSDK.VerbObjectPatch},
		nativeschema.MethodDeleteObject: {sessionSDK.VerbObjectDelete},
		nativeschema.MethodGetObject:    {sessionSDK.VerbObjectGet},
		nativeschema.MethodHeadObject: {
			sessionSDK.VerbObjectHead,
			sessionSDK.VerbObjectGet,
			sessionSDK.VerbObjectDelete,
			sessionSDK.VerbObjectRange,
			sessionSDK.VerbObjectRangeHash,
			sessionSDK.VerbObjectPatch,
		},
		nativeschema.MethodRangeObject:  {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash, sessionSDK.VerbObjectPatch},
		nativeschema.MethodHashObject:   {sessionSDK.VerbObjectRangeHash},
		nativeschema.MethodSearchObject: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete},
		nativeschema.MethodPatchObject:  {sessionSDK.VerbObjectPatch},
	}

	verbs := []sessionSDK.ObjectVerb{
		sessionSDK.VerbObjectPut,
		sessionSDK.VerbObjectDelete,
		sessionSDK.VerbObjectHead,
		sessionSDK.VerbObjectRange,
		sessionSDK.VerbObjectRangeHash,
		sessionSDK.VerbObjectGet,
		sessionSDK.VerbObjectSearch,
		sessionSDK.VerbObjectPatch,
	}

	var tok sessionSDK.Object

	for op, list := range table {
		for _, verb := range verbs {
			contains := slices.Contains(list, verb)

			tok.ForVerb(verb)

			require.Equal(t, contains, assertVerb(tok, op),
				"%v in token, %s executing", verb, op)
		}
	}
}

func TestAssertSessionRelation(t *testing.T) {
	var tok sessionSDK.Object
	cnr := cidtest.ID()
	cnrOther := cidtest.ID()
	obj := oidtest.ID()
	objOther := oidtest.ID()

	// make sure ids differ, otherwise test won't work correctly
	require.False(t, cnrOther.Equals(cnr))
	require.False(t, objOther.Equals(obj))

	// bind session to the container (required)
	tok.BindContainer(cnr)

	// test container-global session
	require.NoError(t, assertSessionRelation(tok, cnr, nil))
	require.NoError(t, assertSessionRelation(tok, cnr, &obj))
	require.Error(t, assertSessionRelation(tok, cnrOther, nil))
	require.Error(t, assertSessionRelation(tok, cnrOther, &obj))

	// limit the session to the particular object
	tok.LimitByObjects(obj)

	// test fixed object session (here obj arg must be non-nil everywhere)
	require.NoError(t, assertSessionRelation(tok, cnr, &obj))
	require.Error(t, assertSessionRelation(tok, cnr, &objOther))
}