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

use tokio::sync::mpsc::{self, Sender, Receiver, error::{TrySendError, TryRecvError}};

use super::{Message, MessageStream, DynMs, MsError, Security};

use crate::world::{MAX_STEPS, player::HumanStyle};
use crate::server::{multiplayer::connection_listener::IncomingConnection, level::{Server as LevelServer, config::Config}};

pub struct LocalMessageStream {
	sender: Sender<Message>,
	receiver: Receiver<Message>,
}

impl LocalMessageStream {
	pub fn new_pair() -> (LocalMessageStream, LocalMessageStream) {
		let ((sender_a, receiver_b), (sender_b, receiver_a)) = (mpsc::channel(MAX_STEPS), mpsc::channel(MAX_STEPS));
		(
			LocalMessageStream { sender: sender_a, receiver: receiver_a },
			LocalMessageStream { sender: sender_b, receiver: receiver_b },
		)
	}

	pub async fn receive_async(&mut self) -> Option<Message> {
		self.receiver.recv().await
	}
}

impl MessageStream for LocalMessageStream {
	fn send(&mut self, msg: Message) -> Result<(), MsError> {
		self.sender.try_send(msg).map_err(|err| match err {
			TrySendError::Full(_) => MsError::Other(String::from("sync sender is full")),
			TrySendError::Closed(_) => MsError::Disconnected(None),
		})
	}

	fn receive(&mut self) -> Result<Option<Message>, MsError> {
		match self.receiver.try_recv() {
			Ok(msg) => Ok(Some(msg)),
			Err(TryRecvError::Empty) => Ok(None),
			Err(TryRecvError::Disconnected) => Err(MsError::Disconnected(None)),
		}
	}

	fn flush(&mut self) -> Result<(), MsError> {
		Ok(())
	}

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

	fn source(&self) -> String {
		String::from("local")
	}

	fn ping(&self) -> Duration {
		Duration::ZERO
	}

	fn security(&self) -> Security {
		Security::Secure
	}
}

impl IncomingConnection for LocalMessageStream {
	fn accept(self: Box<Self>) -> Box<DynMs> { self }
	fn reject(self: Box<Self>, _reason: String) {}
	fn source(&self) -> String { MessageStream::source(self) }
}

pub struct SingleplayerMessageStream {
	stream: LocalMessageStream,
	server: LevelServer,
	dt: f32,
}

impl SingleplayerMessageStream {
	pub fn try_new(config: Arc<Config>, config_path: PathBuf, style: HumanStyle, sanity_checks: bool, spectate: bool) -> Result<(Message, SingleplayerMessageStream), String> {
		let (mut stream_a, stream_b) = LocalMessageStream::new_pair();

		let server = LevelServer::try_new(config, config_path, style, stream_b, sanity_checks, spectate).map_err(|err| format!("failed creating server: {err}"))?;
		let init_msg = stream_a.receiver.try_recv().map_err(|err| format!("failed receiving initial message: {err}"))?;
		let stream = SingleplayerMessageStream { stream: stream_a, server, dt: 0.0 };
		Ok((init_msg, stream))
	}

	pub fn set_dt(&mut self, dt: f32) {
		self.dt = dt;
	}
}

impl MessageStream for SingleplayerMessageStream {
	fn send(&mut self, msg: Message) -> Result<(), MsError> { self.stream.send(msg) }
	fn receive(&mut self) -> Result<Option<Message>, MsError> { self.stream.receive() }

	fn flush(&mut self) -> Result<(), MsError> {
		self.server.update(self.dt).map_err(|err| MsError::Other(format!("server update failed: {err}")))?;
		self.stream.flush()
	}

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

	fn ping(&self) -> Duration {
		Duration::ZERO
	}

	fn security(&self) -> Security {
		Security::Secure
	}
}
