// 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, request::PlayRequest};

#[tokio::test]
async fn magic_number() {
	check_nothing(&[]).await;
	check_nothing(b"jasljasklfj").await;
	check_nothing(b"serp_jasdklj").await;
	check_nothing(b"Serp").await;
	check_nothing(b"SERP_jasdklj").await;
}

async fn check_nothing(data: &[u8]) {
	assert_eq!(request(data).await, Output::Nothing);
}

#[tokio::test]
async fn invalid() {
	check_invalid(request(b"seRp").await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 0]).await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 255]).await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 0, 1]).await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 2, 1, 2, 3, 4]).await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 4, 0]).await);
	check_invalid(request(&[b's', b'e', b'R', b'p', 4, 0, 0, 50, 0]).await);
}

fn check_invalid(out: Output) {
	assert!(matches!(out, Output::Fail(RawFailureResponse::Invalid(_))));
}

#[tokio::test]
async fn bad_payload() {
	let data = [b's', b'e', b'R', b'p', 20, 0, 5, 17, 4, b't', 255, /* Invalid UTF-8 */ b's', b't', 0, 6, b'P', b'l', b'a', b'y', b'e', b'r', 255, 0, 0, 0];
	let out = request(&data).await;
	assert!(matches!(out, Output::Fail(RawFailureResponse::BadPayload(Vu30::ZERO, _))));
}

#[tokio::test]
async fn too_long() {
	assert!(matches!(request(&[b's', b'e', b'R', b'p', 255, 255, 255, 255]).await, Output::Fail(RawFailureResponse::TooLong(_, _))));
}

#[tokio::test]
async fn unsupported_protocol() {
	assert!(matches!(request(&[b's', b'e', b'R', b'p', 6, 255, 255, 255, 255, 0, 0]).await, Output::Fail(RawFailureResponse::UnsupportedProtocol(_))));
}

#[tokio::test]
async fn unsupported_version() {
	let out = request(&[b's', b'e', b'R', b'p', 3, 0, 0, 0]).await;
	assert!(matches!(out, Output::Fail(RawFailureResponse::UnsupportedVersion { index: Vu30::ZERO, supported_version: PlayRequest::PROTOCOL_VERSION, msg: _ })));
}

#[tokio::test]
async fn multiple_subrequests() {
	assert_eq!(request(&[b's', b'e', b'R', b'p', 8, 1, 0, 0, 1, 63, 2, 255, 123]).await, Output::Pass(Request::Info, Vu30::ZERO));
	assert_eq!(request(&[b's', b'e', b'R', b'p', 6, 20, 63, 0, 2, 0, 0]).await, Output::Pass(Request::Discover, Vu30::from_u8(1)));
	assert_eq!(request(&[b's', b'e', b'R', b'p', 9, 0, 0, 0, 20, 63, 0, 2, 0, 0]).await, Output::Pass(Request::Discover, Vu30::from_u8(2)));
	assert_eq!(request(&[b's', b'e', b'R', b'p', 9, 0, 0, 0, 2, 0, 0, 0, 0, 0]).await, Output::Pass(Request::Discover, Vu30::from_u8(1)));
}

#[derive(Debug, PartialEq, Eq)]
enum Output {
	Pass(Request, Vu30), // Success or Understood
	Nothing,
	Fail(RawFailureResponse),
}

async fn request(request: &[u8]) -> Output {
	match Server::recv_with(&mut MockReader(request)).await {
		Ok((request, subrequest_index)) => Output::Pass(request, subrequest_index),
		Err(Or::Both(_, response) | Or::B(response)) => Output::Fail(response),
		Err(Or::A(_)) => Output::Nothing,
	}
}
