package irtt

import (
	"bytes"
	"fmt"
	"testing"
	"time"
)

// request & reply

var testFiller = NewPatternFiller([]byte{0xff, 0xfe, 0xfd, 0xfc})

// request

const testReqCtoken = ctoken(0x886bc9a722b33eea)

const testReqSeqno = Seqno(0x6fe2a1bb)

var testReqHMACKey = []byte{0x3c, 0x68, 0x1d, 0x39, 0x41, 0x1d, 0x72, 0x43}

var testReqBytes = []byte{0x14, 0xa7, 0x5b, 0x8, 0xe7, 0x3, 0x41, 0xe7, 0xd4,
	0x8, 0xcf, 0x69, 0x41, 0xf3, 0xf4, 0x78, 0x5a, 0x56, 0xc, 0x4c, 0xea, 0x3e,
	0xb3, 0x22, 0xa7, 0xc9, 0x6b, 0x88, 0xbb, 0xa1, 0xe2, 0x6f, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0xfd, 0xfc, 0xff, 0xfe,
	0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfc}

// reply

const testRepCtoken = ctoken(0xe666ceb6766fcbc3)

const testRepSeqno = Seqno(0x1d3b0706)

var testRepHMACKey = []byte{0xda, 0xb3, 0xe9, 0x04, 0xa6, 0x87, 0x92, 0x49}

var testRepReceivedCount = ReceivedCount(0xa3bc9f19)

var testRepReceivedWindow = ReceivedWindow(0xd7e939e586f83b9b)

var testRepTimestamp = Timestamp{
	Time{0x525af13dee2a75a1, time.Duration(0x2d5562223e4ac69a)},
	Time{0x589705d446293f69, time.Duration(0x461df12fdd2c5066)},
}

var testRepBytes = []byte{0x14, 0xa7, 0x5b, 0x8, 0xd2, 0x98, 0xa3, 0x4a, 0x6a,
	0x13, 0x41, 0x2, 0x68, 0xb2, 0x67, 0xa8, 0xd6, 0x7e, 0x28, 0x25, 0xc3, 0xcb,
	0x6f, 0x76, 0xb6, 0xce, 0x66, 0xe6, 0x6, 0x7, 0x3b, 0x1d, 0x19, 0x9f, 0xbc,
	0xa3, 0x9b, 0x3b, 0xf8, 0x86, 0xe5, 0x39, 0xe9, 0xd7, 0xa1, 0x75, 0x2a, 0xee,
	0x3d, 0xf1, 0x5a, 0x52, 0x9a, 0xc6, 0x4a, 0x3e, 0x22, 0x62, 0x55, 0x2d, 0x69,
	0x3f, 0x29, 0x46, 0xd4, 0x5, 0x97, 0x58, 0x66, 0x50, 0x2c, 0xdd, 0x2f, 0xf1,
	0x1d, 0x46, 0xff, 0xfe, 0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfc, 0xff, 0xfe, 0xfd,
	0xfc, 0xff, 0xfe, 0xfd, 0xfc}

// TestRequestPacket tests a typical filled request with HMAC.
func TestRequestPacket(t *testing.T) {
	p := newPacket(0, maxHeaderLen, testReqHMACKey)
	p.setConnToken(testReqCtoken)
	p.addFields(fechoRequest, true)
	p.zeroReceivedStats(ReceivedStatsBoth)
	p.stampZeroes(AtBoth, BothClocks)
	p.setSeqno(testReqSeqno)
	p.setLen(256)
	err := p.readPayload(testFiller)
	if err != nil {
		t.Error(err)
	}
	p.updateHMAC()
	t.Logf("Request bytes:\n% x", p.bytes())
	//t.Log(byteArrayLiteral(p.bytes()))
	if !bytesEqual(p.bytes(), testReqBytes) {
		t.Errorf("Unexpected request bytes:\nexpected:\n% x\ngot:\n% x",
			testReqBytes, p.bytes())
	}
}

// TestReplyPacket tests a typical filled reply with HMAC.
func TestReplyPacket(t *testing.T) {
	p := newPacket(0, maxHeaderLen, testRepHMACKey)
	p.setConnToken(testRepCtoken)
	p.addFields(fechoReply, true)

	p.addReceivedStatsFields(ReceivedStatsBoth)
	p.setReceivedCount(testRepReceivedCount)
	p.setReceivedWindow(testRepReceivedWindow)

	p.addTimestampFields(AtBoth, BothClocks)
	p.setTimestamp(AtBoth, testRepTimestamp)

	p.setSeqno(testRepSeqno)
	p.setLen(256)
	err := p.readPayload(testFiller)
	if err != nil {
		t.Error(err)
	}
	p.updateHMAC()
	t.Logf("Reply bytes:\n% x", p.bytes())
	//t.Log(byteArrayLiteral(p.bytes()))
	if !bytesEqual(p.bytes(), testRepBytes) {
		t.Errorf("Unexpected reply bytes:\nexpected:\n% x\ngot:\n% x",
			testRepBytes, p.bytes())
	}
}

func byteArrayLiteral(b []byte) string {
	buf := bytes.NewBufferString("")
	fmt.Fprint(buf, "[]byte{")
	for i, x := range b {
		if i != 0 {
			fmt.Fprint(buf, ",")
		}
		fmt.Fprint(buf, " ")

		fmt.Fprintf(buf, "0x%x", x)
	}
	fmt.Fprint(buf, " }")
	return buf.String()
}
