package byteRange

import "testing"

import "seekia/internal/messaging/inbox"

import "slices"

func TestCompareIdentityBounds(t *testing.T){

	testBound1, testBound2 := GetMinimumMaximumIdentityHashBounds()

	areEqual, latterIsLarger, err := compareByteSlices(testBound1[:], testBound2[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 1 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 1a.")
	}
	if (latterIsLarger == false){
		t.Fatal("compareByteSlices failed test 1b.")
	}

	areEqual, latterIsLarger, err = compareByteSlices(testBound2[:], testBound1[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 2 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 2a.")
	}
	if (latterIsLarger == true){
		t.Fatal("compareByteSlices failed test 2b.")
	}
}

func TestCompareInboxBounds(t *testing.T){

	testBound1 := "5555555555555555"
	testBound2 := "7777777777777777"

	testBound1Bytes, err := inbox.ReadInboxString(testBound1)
	if (err != nil) {
		t.Fatal("testBound1 is invalid: " + err.Error())
	}

	testBound2Bytes, err := inbox.ReadInboxString(testBound2)
	if (err != nil) {
		t.Fatal("testBound2 is invalid: " + err.Error())
	}

	areEqual, latterIsLarger, err := compareByteSlices(testBound1Bytes[:], testBound2Bytes[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 3 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 3a.")
	}
	if (latterIsLarger == false){
		t.Fatal("compareByteSlices failed test 3b.")
	}

	areEqual, latterIsLarger, err = compareByteSlices(testBound2Bytes[:], testBound1Bytes[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 4 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 4a.")
	}
	if (latterIsLarger == true){
		t.Fatal("compareByteSlices failed test 4b.")
	}

	testBound3 := "seekia2222222222"
	testBound4 := "seekia3333333333"

	testBound3Bytes, err := inbox.ReadInboxString(testBound3)
	if (err != nil) {
		t.Fatal("testBound3 is invalid: " + err.Error())
	}

	testBound4Bytes, err := inbox.ReadInboxString(testBound4)
	if (err != nil) {
		t.Fatal("testBound4 is invalid: " + err.Error())
	}

	areEqual, latterIsLarger, err = compareByteSlices(testBound3Bytes[:], testBound4Bytes[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 5 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 5a.")
	}
	if (latterIsLarger == false){
		t.Fatal("compareByteSlices failed test 5b.")
	}

	areEqual, latterIsLarger, err = compareByteSlices(testBound4Bytes[:], testBound3Bytes[:])
	if (err != nil){
		t.Fatal("compareByteSlices failed test 6 with error: " + err.Error())
	}
	if (areEqual == true){
		t.Fatal("compareByteSlices failed test 6a.")
	}
	if (latterIsLarger == true){
		t.Fatal("compareByteSlices failed test 6b.")
	}
}


func TestInboxIsWithinRangeFunction(t *testing.T){

	testRangeStartString := "aaaaaaaaaaaaaaaa"
	testRangeEndString := "5555555555555555"

	testRangeStart, err := inbox.ReadInboxString(testRangeStartString)
	if (err != nil) {
		t.Fatal("testRangeStart is invalid: " + err.Error())
	}

	testRangeEnd, err := inbox.ReadInboxString(testRangeEndString)
	if (err != nil) {
		t.Fatal("testRangeEnd is invalid: " + err.Error())
	}

	inboxAString := "ffffffffffffffff"
	inboxBString := "6666666666666666"

	inboxA, err := inbox.ReadInboxString(inboxAString)
	if (err != nil) {
		t.Fatal("inboxAString is invalid: " + err.Error())
	}

	inboxB, err := inbox.ReadInboxString(inboxBString)
	if (err != nil) {
		t.Fatal("inboxBString is invalid: " + err.Error())
	}

	isWithinRange, err := CheckIfInboxIsWithinRange(testRangeStart, testRangeEnd, inboxA)
	if (err != nil){
		t.Fatal("CheckIfInboxIsWithinRange failed test 1 with error: " + err.Error())
	}
	if (isWithinRange == false){
		t.Fatal("CheckIfInboxIsWithinRange failed test 1.")
	}

	isWithinRange, err = CheckIfInboxIsWithinRange(testRangeStart, testRangeEnd, inboxB)
	if (err != nil){
		t.Fatal("CheckIfInboxIsWithinRange failed test 2 with error: " + err.Error())
	}
	if (isWithinRange == true){
		t.Fatal("CheckIfInboxIsWithinRange failed test 2.")
	}
}

func TestGetInboxesWithinRangeFunction(t *testing.T){

	testRangeStartString := "aaaaaaaaaaaaaaaa"
	testRangeEndString := "5555555555555555"

	testRangeStart, err := inbox.ReadInboxString(testRangeStartString)
	if (err != nil) {
		t.Fatal("testRangeStart is invalid: " + err.Error())
	}

	testRangeEnd, err := inbox.ReadInboxString(testRangeEndString)
	if (err != nil) {
		t.Fatal("testRangeEnd is invalid: " + err.Error())
	}

	inRangeInbox1String := "aaaaaaaaaaaaaaaa"
	inRangeInbox2String := "bbbbbbbbbbbbbbbb"
	inRangeInbox3String := "cccccccccccccccc"
	inRangeInbox4String := "seekia2222222222"

	inRangeInbox1, err := inbox.ReadInboxString(inRangeInbox1String)
	if (err != nil) {
		t.Fatal("inRangeInbox1String is invalid: " + err.Error())
	}

	inRangeInbox2, err := inbox.ReadInboxString(inRangeInbox2String)
	if (err != nil) {
		t.Fatal("inRangeInbox2String is invalid: " + err.Error())
	}

	inRangeInbox3, err := inbox.ReadInboxString(inRangeInbox3String)
	if (err != nil) {
		t.Fatal("inRangeInbox3String is invalid: " + err.Error())
	}

	inRangeInbox4, err := inbox.ReadInboxString(inRangeInbox4String)
	if (err != nil) {
		t.Fatal("inRangeInbox4String is invalid: " + err.Error())
	}

	outOfRangeInbox1String := "6543222222seekia"
	outOfRangeInbox2String := "7777777777777777"

	outOfRangeInbox1, err := inbox.ReadInboxString(outOfRangeInbox1String)
	if (err != nil) {
		t.Fatal("outOfRangeInbox1String is invalid: " + err.Error())
	}

	outOfRangeInbox2, err := inbox.ReadInboxString(outOfRangeInbox2String)
	if (err != nil) {
		t.Fatal("outOfRangeInbox2String is invalid: " + err.Error())
	}

	inputList := [][10]byte{inRangeInbox1, outOfRangeInbox1, inRangeInbox2, outOfRangeInbox2, inRangeInbox3, inRangeInbox4}

	expectedOutputList := [][10]byte{inRangeInbox1, inRangeInbox2, inRangeInbox3, inRangeInbox4}

	anyInboxesFound, inRangeInboxesList, err := GetAllInboxesInListWithinRange(testRangeStart, testRangeEnd, inputList)
	if (err != nil){
		t.Fatal("GetAllInboxesInListWithinRange failed with error: " + err.Error())
	}
	if (anyInboxesFound == false){
		t.Fatal("GetAllInboxesInListWithinRange failed to return any inboxes.")
	}

	if (len(inRangeInboxesList) != 4){
		t.Fatal("GetAllInboxesInListWithinRange returning invalid length result.")
	}

	areEqual := slices.Equal(inRangeInboxesList, expectedOutputList)
	if (areEqual == false){
		t.Fatal("GetAllInboxesInListWithinRange returning invalid in range values list.")
	}
}


func TestGetInboxIntersectionRangeFunction(t *testing.T){

	testBound1String := "aaaaaaaaaaaaaaaa"
	testBound2String := "bbbbbbbbbbbbbbbb"
	testBound3String := "cccccccccccccccc"
	testBound4String := "dddddddddddddddd"

	testBound1, err := inbox.ReadInboxString(testBound1String)
	if (err != nil) {
		t.Fatal("testBound1String is invalid: " + err.Error())
	}
	testBound2, err := inbox.ReadInboxString(testBound2String)
	if (err != nil) {
		t.Fatal("testBound2String is invalid: " + err.Error())
	}
	testBound3, err := inbox.ReadInboxString(testBound3String)
	if (err != nil) {
		t.Fatal("testBound3String is invalid: " + err.Error())
	}
	testBound4, err := inbox.ReadInboxString(testBound4String)
	if (err != nil) {
		t.Fatal("testBound4String is invalid: " + err.Error())
	}

	anyIntersectionFound, _, _, err := GetInboxIntersectionRangeFromTwoRanges(testBound1, testBound2, testBound3, testBound4)
	if (err != nil){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 1 with error: " + err.Error())
	}
	if (anyIntersectionFound == true){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 1")
	}
	
	anyIntersectionFound, intersectionRangeStart, intersectionRangeEnd, err := GetInboxIntersectionRangeFromTwoRanges(testBound1, testBound3, testBound2, testBound4)
	if (err != nil){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 2 with error: " + err.Error())
	}
	if (anyIntersectionFound == false){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 2: No intersection found.")
	}

	if (intersectionRangeStart != testBound2 || intersectionRangeEnd != testBound3){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 2.")
	}

	anyIntersectionFound, intersectionRangeStart, intersectionRangeEnd, err = GetInboxIntersectionRangeFromTwoRanges(testBound1, testBound4, testBound2, testBound3)
	if (err != nil){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 3 with error: " + err.Error())
	}
	if (anyIntersectionFound == false){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 3: No intersection found.")
	}

	if (intersectionRangeStart != testBound2 || intersectionRangeEnd != testBound3){
		t.Fatal("GetInboxIntersectionRangeFromTwoRanges failed test 3.")
	}
}

func TestGetInboxEstimatedItemsInSubrange(t *testing.T){

	testBound1String := "aaaaaaaaaaaaaaaa" // == 0
	testBound2String := "bbbbbbbbbbbbbbbb" // == 1
	testBound3String := "cccccccccccccccc" // == 2
	testBound4String := "dddddddddddddddd" // == 3
	testBound5String := "eeeeeeeeeeeeeeee" // == 4
	testBound6String := "ffffffffffffffff" // == 5
	testBound7String := "gggggggggggggggg" // == 6

	testBound1, err := inbox.ReadInboxString(testBound1String)
	if (err != nil) {
		t.Fatal("testBound1String is invalid: " + err.Error())
	}
	testBound2, err := inbox.ReadInboxString(testBound2String)
	if (err != nil) {
		t.Fatal("testBound2String is invalid: " + err.Error())
	}
	testBound3, err := inbox.ReadInboxString(testBound3String)
	if (err != nil) {
		t.Fatal("testBound3String is invalid: " + err.Error())
	}
	testBound4, err := inbox.ReadInboxString(testBound4String)
	if (err != nil) {
		t.Fatal("testBound4String is invalid: " + err.Error())
	}
	testBound5, err := inbox.ReadInboxString(testBound5String)
	if (err != nil) {
		t.Fatal("testBound5String is invalid: " + err.Error())
	}
	testBound6, err := inbox.ReadInboxString(testBound6String)
	if (err != nil) {
		t.Fatal("testBound6String is invalid: " + err.Error())
	}
	testBound7, err := inbox.ReadInboxString(testBound7String)
	if (err != nil) {
		t.Fatal("testBound7String is invalid: " + err.Error())
	}

	estimatedItems, err := GetEstimatedInboxSubrangeQuantity(testBound1, testBound7, 100, testBound2, testBound5)
	if (err != nil){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 1 with error: " + err.Error())
	}
	if (estimatedItems != 50){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 1.")
	}

	estimatedItems, err = GetEstimatedInboxSubrangeQuantity(testBound1, testBound6, 100, testBound1, testBound2)
	if (err != nil){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 2 with error: " + err.Error())
	}
	if (estimatedItems != 20){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 2.")
	}

	estimatedItems, err = GetEstimatedInboxSubrangeQuantity(testBound1, testBound6, 100, testBound3, testBound4)
	if (err != nil){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 3 with error: " + err.Error())
	}
	if (estimatedItems != 20){
		t.Fatal("GetEstimatedInboxSubrangeQuantity failed test 3.")
	}
}


func TestSplitIntoSubrangesFunction(t *testing.T){

	testBound1String := "aaaaaaaaaaaaaaaa"
	testBound2String := "cccccccccccccccc"

	testBound1, err := inbox.ReadInboxString(testBound1String)
	if (err != nil) {
		t.Fatal("testBound1String is invalid: " + err.Error())
	}
	testBound2, err := inbox.ReadInboxString(testBound2String)
	if (err != nil) {
		t.Fatal("testBound2String is invalid: " + err.Error())
	}

	subrangesList, err := SplitInboxRangeIntoEqualSubranges(testBound1, testBound2, 100, 50)
	if (err != nil){
		t.Fatal("SplitInboxRangeIntoEqualSubranges failed with error: " + err.Error())
	}

	if (len(subrangesList) != 2){
		t.Fatal("SplitInboxRangeIntoEqualSubranges failed: Subranges list not 2 items in length.")
	}

	subrange1StartString := "aaaaaaaaaaaaaaaa"
	subrange1EndString := "bbbbbbbbbbbbbbbb"

	subrange2StartString := "bbbbbbbbbbbbbbbc"
	subrange2EndString := "cccccccccccccccc"

	subrange1Start, err := inbox.ReadInboxString(subrange1StartString)
	if (err != nil) {
		t.Fatal("subrange1StartString is invalid: " + err.Error())
	}
	subrange1End, err := inbox.ReadInboxString(subrange1EndString)
	if (err != nil) {
		t.Fatal("subrange1EndString is invalid: " + err.Error())
	}

	subrange2Start, err := inbox.ReadInboxString(subrange2StartString)
	if (err != nil) {
		t.Fatal("subrange2StartString is invalid: " + err.Error())
	}
	subrange2End, err := inbox.ReadInboxString(subrange2EndString)
	if (err != nil) {
		t.Fatal("subrange2EndString is invalid: " + err.Error())
	}

	subrange1 := InboxSubrange{
		SubrangeStart: subrange1Start,
		SubrangeEnd: subrange1End,
	}

	subrange2 := InboxSubrange{

		SubrangeStart: subrange2Start,
		SubrangeEnd: subrange2End,
	}

	expectedSubrangesList := []InboxSubrange{subrange1, subrange2}
	
	areEqual := slices.Equal(subrangesList, expectedSubrangesList)
	if (areEqual == false){
		t.Fatal("SplitInboxRangeIntoEqualSubranges failed: Expected map list does not match.")
	}


}
