// clang-format off
#include <GPS_NMEA.hpp>
#include <iostream>
#include <cstring>
#include <get_field.hpp>
#include <CppUTest/CommandLineTestRunner.h>
// clang-format on

TEST_GROUP(GPS_NMEATestGroup)
{
	// Contents of this valid msg is taken from pg 38 of UBlox manual:
	// https://content.u-blox.com/sites/default/files/u-blox-M9-SPG-4.04_InterfaceDescription_UBX-21022436.pdf
	const char* valid_pubx00_msg = "$PUBX,00,081350.00,4717.113210,N,00833.915187,E,546.589,G3,2.1,"
								   "2.0,0.007,77.52,0.007,,0.92,1.19,0.77,9,0,0*5F\r\n";
	const uint8_t valid_pubx00_msg_crc = uint8_t(0x5F);

	// Same as above but changed PUBX to PUBY - checksum at end thus INVALID
	const char* corrupt_pubx00_msg = "$PUBY,00,081350.00,4717.113210,N,00833.915187,E,546.589,G3,2."
									 "1,2.0,0.007,77.52,0.007,,0.92,1.19,0.77,9,0,0*5F\r\n";
};

TEST(GPS_NMEATestGroup, ChecksumCalcProducesKnownAnswer)
{
	auto reinterpreted_input_pointer =
		reinterpret_cast<uint8_t*>(const_cast<char*>(valid_pubx00_msg));
	uint8_t computed_crc =
		GPS_NMEA::computeChecksum(reinterpreted_input_pointer, strlen(valid_pubx00_msg));
	CHECK_EQUAL(valid_pubx00_msg_crc, computed_crc);
}

TEST(GPS_NMEATestGroup, NMEA0183SentenceValid_works)
{
	// Pass a known good sentence
	auto reinterpreted_input_pointer =
		reinterpret_cast<uint8_t*>(const_cast<char*>(valid_pubx00_msg));
	bool result = GPS_NMEA::sentenceValid(reinterpreted_input_pointer, strlen(valid_pubx00_msg));
	CHECK(result);

	// Send a corrupted sentence (a PUBY message)
	reinterpreted_input_pointer = reinterpret_cast<uint8_t*>(const_cast<char*>(corrupt_pubx00_msg));
	result = GPS_NMEA::sentenceValid(reinterpreted_input_pointer, strlen(corrupt_pubx00_msg));
	CHECK_FALSE(result);
}

TEST(GPS_NMEATestGroup, NMEAStrings_to_decimalDegs)
{
	std::string field = getField(valid_pubx00_msg, ",", 3);
	double computed_lat = GPS_NMEA::lat2DD(field);

	const double precision = 0.000001;

	// working with 4717.113210. Compute manually
	double correctDecimal_deg = 47.0 + 17.113210 / 60.0;
	DOUBLES_EQUAL(correctDecimal_deg, computed_lat, precision);

	field = getField(valid_pubx00_msg, ",", 5);
	double computed_lon = GPS_NMEA::lon2DD(field);
	// working with 00833.915187. Compute manually
	correctDecimal_deg = 8.0 + 33.915187 / 60.0;
	DOUBLES_EQUAL(correctDecimal_deg, computed_lon, precision);
}
