package handlers_test

import (
	"fmt"
	"net/http"
	"testing"

	"otaupdate/handlers"
	"otaupdate/utils"

	th "github.com/fiskerinc/cloud-services/pkg/testhelper"
)

var testInput = firstRecord + "\n" + secondRecord + "\n" + thirdRecord + "\n" + fourthRecord + "\n" + fifthRecord + "\n" + sixthRecord

var firstRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:49.323538","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122482177"}`
var secondRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:49.225069","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122502977"}`
var thirdRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:51.932326","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122710681"}`
var fourthRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:51.842027","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122736981"}`
var fifthRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:51.729643","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122761582"}`
var sixthRecord = `{"level":"debug","timestamp":"2023-Jan-25 22:50:52.343492","line_number":0,"filename":"dummy","msg":"vom::on_frame_() frame 0x52","received_timestamp":"2023-Jan-25 22:51:10.122779382"}`

var (
	testVin           = "1G1FP87S1GN000414"
	testYear          = 2023
	testMonth         = 1
	testDay           = 17
	testOffset        = 0
	testCount         = 0
	testReadDirection = utils.Up
)

func formatRequest(request string) string {
	return fmt.Sprintf(request, testVin, testYear, testMonth, testDay, testOffset, testCount,
		func() string {
			if testReadDirection == utils.Up {
				return "UP"
			} else {
				return "DOWN"
			}
		}())
}

func addTest(t *testing.T, name, expectectedResponse string) {
	handlers.ReadAzureBlobFun = createTestReader(t, testVin, testYear, testMonth, testDay, testOffset, testCount, testReadDirection)
	test := th.BasicHttpTest{
		Name: name,
		Request: th.MakeTestRequest(http.MethodGet,
			formatRequest("http://example.com/vehicle/%s/trex-logs?&date=%d-%02d-%d&offset=%d&count=%d&direction=%s"), nil),
		ExpectedStatus:   http.StatusOK,
		ExpectedResponse: expectectedResponse,
	}
	th.RunParamHttpTest(t, test, handlers.HandleTrexLogsGet, "/vehicle/:vin/trex-logs")
}

func createTestReader(t *testing.T, testVin string, testYear, testMonth, testDay, testOffset, testCount int, testReadDirection utils.Direction) func(string, string, int, int, int, int64, int64, utils.Direction) ([]byte, int64, error) {
	return func(path, vin string, year, month, day int, offset, count int64, readDirection utils.Direction) ([]byte, int64, error) {
		var check = func(format string, actual, expected interface{}) {
			if actual != expected {
				t.Fatalf(format, expected, actual)
			}
		}
		check("expected vin: %s, got: %s", vin, testVin)
		check("expected year: %d, got: %d", year, testYear)
		check("expected month: %d, got: %d", month, testMonth)
		check("expected day: %d, got: %d", day, testDay)
		check("expected offset: %d, got: %d", offset, int64(testOffset))
		check("expected count: %d, got: %d", count, int64(testCount))
		check("expected direction: %d, got: %d", readDirection, testReadDirection)
		//count from the end

		offset = int64(len(testInput)) - offset

		begin := offset
		if readDirection == utils.Up {
			begin -= count
		}
		if begin <= 0 {
			begin = 0
			count = offset
		}
		min := func(a, b int64) int64 {
			if a < b {
				return a
			}
			return b
		}
		max := func(a, b int64) int64 {
			if a > b {
				return a
			}
			return b
		}

		begin = max(0, begin)

		return []byte(testInput)[begin : begin+min(count, int64(len(testInput))-begin)], int64(len(testInput)), nil
	}
}

func TestTrexLogsGet(t *testing.T) {
	testCount = 300
	testLen := int64(len(testInput))
	//expect that we read exactly 1 record
	addTest(t, "Read 1 record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, sixthRecord, testOffset, len(sixthRecord)+1, testLen))
	testCount = 100
	//read nothing (100 < len(sixthRecord))
	addTest(t, "Read 0 record",
		fmt.Sprintf(`{"data":[],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, testOffset, 0, testLen))
	//read all
	testCount = len(testInput)
	addTest(t, "Read all records",
		fmt.Sprintf(`{"data":[%s,%s,%s,%s,%s,%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`,
			firstRecord, secondRecord, thirdRecord, fourthRecord, fifthRecord, sixthRecord, testOffset, testCount, testLen))
	//something a little big bigger than 1 record
	testCount = len(sixthRecord) + 25
	testOffset = 0
	//read 1 by 1 from the bottom
	addTest(t, "Read sixth record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, sixthRecord, testOffset, len(sixthRecord)+1, testLen))
	testOffset += len(sixthRecord) + 1
	addTest(t, "Read fifth record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, fifthRecord, testOffset, len(fifthRecord)+1, testLen))
	testOffset += len(fifthRecord) + 1
	addTest(t, "Read fourth record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, fourthRecord, testOffset, len(fourthRecord)+1, testLen))
	testOffset += len(fourthRecord) + 1
	addTest(t, "Read third record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, thirdRecord, testOffset, len(thirdRecord)+1, testLen))
	testOffset += len(thirdRecord) + 1
	addTest(t, "Read second record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, secondRecord, testOffset, len(secondRecord)+1, testLen))
	testOffset += len(secondRecord) + 1
	addTest(t, "Read first record", //+1 is for \n
		fmt.Sprintf(`{"data":[%s],"RealOffset":%d,"bytesRead":%d,"blobSize":%d}`, firstRecord, testOffset, len(firstRecord), testLen))
}
