package netmap

import (
	"testing"

	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap"
	"github.com/stretchr/testify/require"
)

func TestNodeInfo_NetworkEndpoints(t *testing.T) {
	t.Run("empty", func(t *testing.T) {
		var n NodeInfo
		for range n.NetworkEndpoints() {
			t.Fatalf("handler is called, but it shouldn't")
		}
	})

	var n NodeInfo
	n.SetNetworkEndpoints("1", "2", "3")

	t.Run("break", func(t *testing.T) {
		var res []string
		for s := range n.NetworkEndpoints() {
			if s == "2" {
				break
			}
			res = append(res, s)
		}
		require.Equal(t, []string{"1"}, res)
	})
	t.Run("continue", func(t *testing.T) {
		var res []string
		for s := range n.NetworkEndpoints() {
			if s == "2" {
				continue
			}
			res = append(res, s)
		}
		require.Equal(t, []string{"1", "3"}, res)
	})

	var res []string
	for s := range n.NetworkEndpoints() {
		res = append(res, s)
	}
	require.Equal(t, []string{"1", "2", "3"}, res)
}

func TestNodeInfo_SetAttribute(t *testing.T) {
	var n NodeInfo

	const key = "some key"
	val := "some value"

	require.Zero(t, n.Attribute(val))

	n.SetAttribute(key, val)
	require.Equal(t, val, n.Attribute(key))

	val = "some other value"

	n.SetAttribute(key, val)
	require.Equal(t, val, n.Attribute(key))
}

func TestNodeState(t *testing.T) {
	m := map[NodeState]netmap.NodeState{
		UnspecifiedState: netmap.UnspecifiedState,
		Online:           netmap.Online,
		Offline:          netmap.Offline,
		Maintenance:      netmap.Maintenance,
	}

	t.Run("from sdk to v2", func(t *testing.T) {
		for stateSDK, stateV2 := range m {
			require.Equal(t, stateV2, stateSDK.ToV2())
		}
	})

	t.Run("from v2 to sdk", func(t *testing.T) {
		for stateSDK, stateV2 := range m {
			var state NodeState
			state.FromV2(stateV2)
			require.Equal(t, stateSDK, state)
		}
	})
}

func TestNodeInfo_Status(t *testing.T) {
	t.Run("deprecated getters/setters", func(t *testing.T) {
		var n NodeInfo

		require.False(t, n.IsOnline())
		require.False(t, n.IsOffline())
		require.False(t, n.IsMaintenance())

		n.SetOnline()
		require.True(t, n.IsOnline())
		require.False(t, n.IsOffline())
		require.False(t, n.IsMaintenance())

		n.SetOffline()
		require.True(t, n.IsOffline())
		require.False(t, n.IsOnline())
		require.False(t, n.IsMaintenance())

		n.SetMaintenance()
		require.True(t, n.IsMaintenance())
		require.False(t, n.IsOnline())
		require.False(t, n.IsOffline())
	})

	t.Run("brand new getters/setters", func(t *testing.T) {
		var n NodeInfo

		require.False(t, n.Status().IsOnline())
		require.False(t, n.Status().IsOffline())
		require.False(t, n.Status().IsMaintenance())

		n.SetStatus(Online)
		require.True(t, n.Status().IsOnline())
		require.False(t, n.Status().IsOffline())
		require.False(t, n.Status().IsMaintenance())

		n.SetStatus(Offline)
		require.False(t, n.Status().IsOnline())
		require.True(t, n.Status().IsOffline())
		require.False(t, n.Status().IsMaintenance())

		n.SetStatus(Maintenance)
		require.False(t, n.Status().IsOnline())
		require.False(t, n.Status().IsOffline())
		require.True(t, n.Status().IsMaintenance())
	})
}

func TestNodeInfo_ExternalAddr(t *testing.T) {
	var n NodeInfo

	require.Empty(t, n.ExternalAddresses())
	require.Panics(t, func() { n.SetExternalAddresses() })

	addr := []string{"1", "2", "3"}
	n.SetExternalAddresses(addr[0])
	require.Equal(t, addr[:1], n.ExternalAddresses())

	n.SetExternalAddresses(addr[1:]...)
	require.Equal(t, addr[1:], n.ExternalAddresses())
}

func TestNodeInfo_Clone(t *testing.T) {
	var ni NodeInfo
	ni.SetPublicKey([]byte{2, 3})

	c := ni.Clone()
	require.True(t, c != &ni)
	require.True(t, &(c.PublicKey()[0]) != &(ni.PublicKey()[0]))
}