// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use super::*;
use super::super::mock_io::MockReader;

#[test]
fn success_ser() {
	cmp(RawResponse::Success(Vu30::ZERO), &[b'S', b'e', b'r', b'p', 0, 0]);
	cmp(RawResponse::Success(Vu30::from_u8(1)), &[b'S', b'e', b'r', b'p', 0, 1]);
	cmp(RawResponse::Success(Vu30::from_u8(64)), &[b'S', b'e', b'r', b'p', 0, 64, 0]);
	cmp(RawResponse::Success(Vu30::from_u8(69)), &[b'S', b'e', b'r', b'p', 0, 69, 0]);
	cmp(RawResponse::Success(Vu30::from_u8(128)), &[b'S', b'e', b'r', b'p', 0, 64, 1]);
	cmp(RawResponse::Success(Vu30::try_from_u32(16384 + 64).unwrap()), &[b'S', b'e', b'r', b'p', 0, 128, 0, 0]);
}

#[test]
fn understood_ser() {
	fcmp(RawFailureResponse::Understood(Vu30::ZERO, String::from("no")), &[b'S', b'e', b'r', b'p', 1, 0, 2, b'n', b'o']);
	fcmp(RawFailureResponse::Understood(Vu30::ZERO, String::from("nope")), &[b'S', b'e', b'r', b'p', 1, 0, 4, b'n', b'o', b'p', b'e']);
}

#[test]
fn error_ser() {
	fcmp(RawFailureResponse::Error(String::new()), &[b'S', b'e', b'r', b'p', 2, 0]);
}

#[test]
fn invalid_ser() {
	fcmp(RawFailureResponse::Invalid(String::from("test")), &[b'S', b'e', b'r', b'p', 3, 4, b't', b'e', b's', b't']);
}

#[test]
fn bad_payload_ser() {
	fcmp(RawFailureResponse::BadPayload(Vu30::ZERO, String::from("data")), &[b'S', b'e', b'r', b'p', 4, 0, 4, b'd', b'a', b't', b'a']);
	fcmp(RawFailureResponse::BadPayload(Vu30::from_u8(5), String::from("xyz")), &[b'S', b'e', b'r', b'p', 4, 5, 3, b'x', b'y', b'z']);
}

#[test]
fn too_log_ser() {
	fcmp(RawFailureResponse::TooLong(Vu30::MAX, String::new()), &[b'S', b'e', b'r', b'p', 5, 255, 255, 255, 255, 0]);
}

#[test]
fn unsupported_protocol_ser() {
	fcmp(RawFailureResponse::UnsupportedProtocol(String::from("unknown")), &[b'S', b'e', b'r', b'p', 6, 7, b'u', b'n', b'k', b'n', b'o', b'w', b'n']);
}

#[test]
fn unsupported_version_ser() {
	fcmp(
		RawFailureResponse::UnsupportedVersion { index: Vu30::from_u8(1), supported_version: Vu30::from_u8(6), msg: String::from("out of date") },
		&[b'S', b'e', b'r', b'p', 7, 1, 6, 11, b'o', b'u', b't', b' ', b'o', b'f', b' ', b'd', b'a', b't', b'e'],
	);
}

fn cmp(response: RawResponse, expected: &[u8]) {
	assert_eq!(response.serialise().unwrap(), expected);
}

fn fcmp(response: RawFailureResponse, expected: &[u8]) {
	assert_eq!(RawResponse::Failure(response).serialise().unwrap(), expected);
}

#[tokio::test]
async fn property() {
	let responses = [
		RawResponse::Success(Vu30::ZERO), RawResponse::Success(Vu30::from_u8(1)), RawResponse::Success(Vu30::MAX),
		RawResponse::Failure(RawFailureResponse::Understood(Vu30::ZERO, String::from("access denied"))),
		RawResponse::Failure(RawFailureResponse::Understood(Vu30::from_u8(1), String::from("too many clients, limit is 69"))),
		RawResponse::Failure(RawFailureResponse::Error(String::from("error"))),
		RawResponse::Failure(RawFailureResponse::Error(String::new())),
		RawResponse::Failure(RawFailureResponse::Invalid(String::from("subrequest payload too long"))),
		RawResponse::Failure(RawFailureResponse::BadPayload(Vu30::ZERO, String::from("failed deserialising"))),
		RawResponse::Failure(RawFailureResponse::TooLong(Vu30::MAX, String::from("impossible"))),
		RawResponse::Failure(RawFailureResponse::TooLong(Vu30::try_from_u32(6969).unwrap(), String::from("very nice"))),
		RawResponse::Failure(RawFailureResponse::UnsupportedProtocol(String::new())),
		RawResponse::Failure(RawFailureResponse::UnsupportedProtocol(String::from("nothing supported"))),
		RawResponse::Failure(RawFailureResponse::UnsupportedVersion { index: Vu30::ZERO, supported_version: Vu30::from_u8(2), msg: String::new() }),
	];

	for response in responses {
		let data = response.serialise().unwrap();
		let response2 = RawResponse::read(&mut MockReader(&data)).await.unwrap();
		assert_eq!(response, response2);
	}
}
