package packet

import (
	"bytes"
	"testing"

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

func TestInitiationMessageMsgType(t *testing.T) {
	pd := &InitiationMessage{
		CommonHeader: &CommonHeader{
			MsgType: 100,
		},
	}

	if pd.MsgType() != 100 {
		t.Errorf("Unexpected result")
	}
}

func TestSerializeInit(t *testing.T) {
	tests := []struct {
		name     string
		input    *InitiationMessage
		expected []byte
	}{
		{
			name: "Test case with all three information types",
			input: &InitiationMessage{
				CommonHeader: &CommonHeader{
					Version: 3,
					MsgType: 4,
				},
				TLVs: []*InformationTLV{
					{
						InformationType: 0,
						Information:     []byte("lorem ipsum dolor sit amet"),
					},
					{
						InformationType: 1,
						Information:     []byte("Juniper Networks, Inc. vmx internet router, kernel FreeBSD JNPR-12.1-20210828.6e5b1bf_buil, Build date: 2021-09-15 21:14:11 UTC Copyright (c) 1996-2021 Juniper Networks, Inc. "),
					},
					{
						InformationType: 2,
						Information:     []byte("edge01.xyz01"),
					},
				},
			},
			expected: []byte{
				0x3,                 // version
				0x0, 0x0, 0x0, 0xe7, // message length
				0x4, // message type

				0x0, 0x0, // information type
				0x0, 0x1a, // information length
				0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70,
				0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
				0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d,
				0x65, 0x74,

				0x0, 0x1, // information type
				0x0, 0xaf, // information length
				0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x20,
				0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,
				0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x76,
				0x6d, 0x78, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72,
				0x6e, 0x65, 0x74, 0x20, 0x72, 0x6f, 0x75, 0x74,
				0x65, 0x72, 0x2c, 0x20, 0x6b, 0x65, 0x72, 0x6e,
				0x65, 0x6c, 0x20, 0x46, 0x72, 0x65, 0x65, 0x42,
				0x53, 0x44, 0x20, 0x4a, 0x4e, 0x50, 0x52, 0x2d,
				0x31, 0x32, 0x2e, 0x31, 0x2d, 0x32, 0x30, 0x32,
				0x31, 0x30, 0x38, 0x32, 0x38, 0x2e, 0x36, 0x65,
				0x35, 0x62, 0x31, 0x62, 0x66, 0x5f, 0x62, 0x75,
				0x69, 0x6c, 0x2c, 0x20, 0x42, 0x75, 0x69, 0x6c,
				0x64, 0x20, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x20,
				0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x39, 0x2d,
				0x31, 0x35, 0x20, 0x32, 0x31, 0x3a, 0x31, 0x34,
				0x3a, 0x31, 0x31, 0x20, 0x55, 0x54, 0x43, 0x20,
				0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
				0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39,
				0x39, 0x36, 0x2d, 0x32, 0x30, 0x32, 0x31, 0x20,
				0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x20,
				0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,
				0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,

				0x0, 0x2, // information type
				0x0, 0xc, // information length
				0x65, 0x64, 0x67, 0x65, 0x30, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x30, 0x31,
			},
		},
	}

	for _, test := range tests {
		buf := bytes.NewBuffer(nil)
		test.input.Serialize(buf)
		assert.Equal(t, test.expected, buf.Bytes(), test.name)
	}
}

func TestDecodeInitiationMessage(t *testing.T) {
	tests := []struct {
		name     string
		input    []byte
		ch       *CommonHeader
		wantFail bool
		expected *InitiationMessage
	}{
		{
			name: "Full",
			input: []byte{
				0, 1, // sysDescr
				0, 4, // Length
				42, 42, 42, 42, // AAAA
				0, 2, //sysName
				0, 5, // Length
				43, 43, 43, 43, 43, // BBBBB
			},
			ch: &CommonHeader{
				MsgLength: CommonHeaderLen + 17,
			},
			wantFail: false,
			expected: &InitiationMessage{
				CommonHeader: &CommonHeader{
					MsgLength: CommonHeaderLen + 17,
				},
				TLVs: []*InformationTLV{
					{
						InformationType:   1,
						InformationLength: 4,
						Information:       []byte{42, 42, 42, 42},
					},
					{
						InformationType:   2,
						InformationLength: 5,
						Information:       []byte{43, 43, 43, 43, 43},
					},
				},
			},
		},
		{
			name: "Incomplete",
			input: []byte{
				0, 1, // sysDescr
				0, 4, // Length
				42, 42, 42, 42, // AAAA
				0, 2, //sysName
				0, 5, // Length
				43, 43, 43, 43, // BBBB
			},
			ch: &CommonHeader{
				MsgLength: CommonHeaderLen + 17,
			},
			wantFail: true,
		},
	}

	for _, test := range tests {
		buf := bytes.NewBuffer(test.input)
		im, err := decodeInitiationMessage(buf, test.ch)
		if err != nil {
			if test.wantFail {
				continue
			}

			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
			continue
		}

		if test.wantFail {
			t.Errorf("Unexpected success for test %q", test.name)
			continue
		}

		assert.Equalf(t, test.expected, im, "Test %q", test.name)
	}
}
