package tree

import (
	"testing"

	"github.com/stretchr/testify/require"
)

type nodeMeta struct {
	key   string
	value []byte
}

func (m nodeMeta) GetKey() string {
	return m.key
}

func (m nodeMeta) GetValue() []byte {
	return m.value
}

type nodeResponse struct {
	meta      []nodeMeta
	timestamp []uint64
}

func (n nodeResponse) GetTimestamp() []uint64 {
	return n.timestamp
}

func (n nodeResponse) GetMeta() []Meta {
	res := make([]Meta, len(n.meta))
	for i, value := range n.meta {
		res[i] = value
	}
	return res
}

func (n nodeResponse) GetNodeID() []uint64 {
	return nil
}
func (n nodeResponse) GetParentID() []uint64 {
	return nil
}

func TestGetLatestNode(t *testing.T) {
	for _, tc := range []struct {
		name        string
		nodes       []NodeResponse
		exceptedOID string
		error       bool
	}{
		{
			name:  "empty",
			nodes: []NodeResponse{},
			error: true,
		},
		{
			name: "one node of the object version",
			nodes: []NodeResponse{
				nodeResponse{
					timestamp: []uint64{1},
					meta: []nodeMeta{
						{
							key:   oidKV,
							value: []byte("oid1"),
						},
					},
				},
			},
			exceptedOID: "oid1",
		},
		{
			name: "one node of the object version and one node of the secondary object",
			nodes: []NodeResponse{
				nodeResponse{
					timestamp: []uint64{3},
					meta:      []nodeMeta{},
				},
				nodeResponse{
					timestamp: []uint64{1},
					meta: []nodeMeta{
						{
							key:   oidKV,
							value: []byte("oid1"),
						},
					},
				},
			},
			exceptedOID: "oid1",
		},
		{
			name: "all nodes represent a secondary object",
			nodes: []NodeResponse{
				nodeResponse{
					timestamp: []uint64{3},
					meta:      []nodeMeta{},
				},
				nodeResponse{
					timestamp: []uint64{5},
					meta:      []nodeMeta{},
				},
			},
			error: true,
		},
		{
			name: "several nodes of different types and with different timestamp",
			nodes: []NodeResponse{
				nodeResponse{
					timestamp: []uint64{1},
					meta: []nodeMeta{
						{
							key:   oidKV,
							value: []byte("oid1"),
						},
					},
				},
				nodeResponse{
					timestamp: []uint64{3},
					meta:      []nodeMeta{},
				},
				nodeResponse{
					timestamp: []uint64{4},
					meta: []nodeMeta{
						{
							key:   oidKV,
							value: []byte("oid2"),
						},
					},
				},
				nodeResponse{
					timestamp: []uint64{6},
					meta:      []nodeMeta{},
				},
			},
			exceptedOID: "oid2",
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			actualNode, err := getLatestVersionNode(tc.nodes)
			if tc.error {
				require.Error(t, err)
				return
			}

			require.NoError(t, err)
			require.Equal(t, tc.exceptedOID, string(actualNode.GetMeta()[0].GetValue()))
		})
	}
}