// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use tokio::sync::mpsc::{Receiver, error::TryRecvError};

use crate::net::serp::request::PlayRequest;
use crate::protocol::message::stream::DynMs;

pub struct ConnectionListener(Receiver<(Box<DynIncomingConnection>, PlayRequest)>);

impl ConnectionListener {
	pub fn new(receiver: Receiver<(Box<DynIncomingConnection>, PlayRequest)>) -> ConnectionListener {
		ConnectionListener(receiver)
	}
}

impl ConnectionListener {
	/**
	 * Returns a pending connection, if it exists.
	 *
	 * On success, if there's a pending connection returns an
	 * `IncomingConnection` in the Ok(Some(...)) variant for a client attempting
	 * to connect. This connection can be accepted to return a `MessageStream` or
	 * rejected with a provided reason. Returns Ok(None) if there's no pending
	 * connection.
	 *
	 * If the server should close for whatever reason, the Err variant should be
	 * returned.
	 *
	 * This method is non-blocking.
	 */
	pub fn get(&mut self) -> Result<Option<(Box<DynIncomingConnection>, PlayRequest)>, ()> {
		match self.0.try_recv() {
			Ok((incoming, request)) => Ok(Some((incoming, request))),
			Err(TryRecvError::Empty) => Ok(None),
			Err(TryRecvError::Disconnected) => Err(()),
		}
	}
}

pub type DynIncomingConnection = dyn IncomingConnection + Send;

/**
 * A connection attempt made by the client. Can be accepted to return a message
 * stream or rejected with a provided reason.
 */
pub trait IncomingConnection {
	fn accept(self: Box<Self>) -> Box<DynMs>;
	fn reject(self: Box<Self>, reason: String);

	fn source(&self) -> String;
}
