// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use std::time::Duration;

use quinn::Connection;

use super::{sender::SenderTask, receiver::{ReceiverTask, ReceiverTaskBuilder}, error::ErrorContainer, super::{MessageStream, MsError, Security}};

use crate::protocol::message::{Message, WorldMessage, MiscMessage, text_io::ClientTextInput};
use crate::net::serp::{InitClient, ConnectionHandle, request::{Request, PlayRequest}};
use crate::world::player::update::PlayerUpdate;

pub struct ClientMessageStream {
	world_sender: SenderTask<(PlayerUpdate, u64)>,
	misc_sender: SenderTask<ClientTextInput>,
	receiver: ReceiverTask,
	conn: ConnectionHandle,
	error: ErrorContainer,
	security: Security,
}

impl ClientMessageStream {
	pub async fn try_new(conn: Connection, request: PlayRequest, security: Security) -> Result<(ClientMessageStream, Message), String> {
		let conn = InitClient::send(conn, Request::Play(request)).await?;

		let mut world_stream = conn.main_stream;
		world_stream.sender.set_priority(1)?;

		let misc_stream = conn.handle.accept_stream().await?;

		let error = ErrorContainer::default();
		let conn = conn.handle;

		let world_sender = SenderTask::new(world_stream.sender, error.clone());
		let misc_sender = SenderTask::new(misc_stream.sender, error.clone());
		let mut receiver_builder = ReceiverTaskBuilder::new(error.clone()).add_stream::<Vec<WorldMessage>>(world_stream.receiver, 1 << 24);
		let init_msg = receiver_builder.receive(&error).await?;
		let receiver = receiver_builder.add_stream::<Vec<MiscMessage>>(misc_stream.receiver, 1 << 24).build();

		Ok((ClientMessageStream { world_sender, misc_sender, receiver, conn, error, security }, init_msg))
	}
}

impl MessageStream for ClientMessageStream {
	fn send(&mut self, msg: Message) -> Result<(), MsError> {
		match msg {
			Message::PlayerUpdate(update, count) => self.world_sender.send((update, count), &self.error)?,
			Message::PlayerBulkUpdate(bulk_update) => {
				let Some(limit) = self.conn.max_datagram_size() else { return Ok(()); };
				let Some(data) = bulk_update.serialise(limit) else { return Ok(()); };
				debug_assert!(data.len() < limit);
				self.conn.send_datagram(data)?;
			},
			Message::ClientTextInput(msg) => self.misc_sender.send(msg, &self.error)?,
			_ => unimplemented!(),
		}

		Ok(())
	}

	fn receive(&mut self) -> Result<Option<Message>, MsError> {
		Ok(self.receiver.receive(&self.error)?)
	}

	fn flush(&mut self) -> Result<(), MsError> {
		/*
		 * No need to buffer messages because only one player update is sent per
		 * frame (and you want these to reach the server as fast as possible), and
		 * it's probably impossible for a user to send multiple chat/command
		 * messages in a single frame.
		 *
		 * Also there is a size disadvantage of sending a Vec<M> compared to
		 * sending an M, if the Vec<M> is always of size 1.
		 */
		Ok(())
	}

	fn is_networked(&self) -> bool {
		true
	}

	fn ping(&self) -> Duration {
		self.conn.rtt()
	}

	fn security(&self) -> Security {
		self.security
	}
}

impl From<WorldMessage> for Message {
	fn from(msg: WorldMessage) -> Message {
		Message::World(msg)
	}
}

impl From<MiscMessage> for Message {
	fn from(msg: MiscMessage) -> Message {
		Message::Misc(msg)
	}
}
