use super::*;
use crate::LogCache;
use jsonrpsee::server::ServerConfig;
use std::sync::Arc;

const MAX_RPC_REQUEST_SIZE: u32 = 64 * 1024;
const MAX_RPC_RESPONSE_SIZE: u32 = 100 * 1024 * 1024;

/// JSON-RPC server configuration.
#[non_exhaustive]
pub struct Config {
	/// Bind address (`IP:PORT`).
	pub listen_addr: String,
	/// Max. no. of clients.
	pub max_connections: u32,
}

impl Default for Config {
	fn default() -> Self {
		Self { listen_addr: "127.0.0.1:18801".into(), max_connections: 1000 }
	}
}

pub struct Server {
	logs: Arc<LogCache>,
}

impl Server {
	pub fn new(logs: Arc<LogCache>) -> Self {
		Self { logs }
	}

	pub async fn run(self, config: Config) -> std::io::Result<()> {
		let server = jsonrpsee::server::Server::builder()
			.set_config(
				ServerConfig::builder()
					.max_request_body_size(MAX_RPC_REQUEST_SIZE)
					.max_response_body_size(MAX_RPC_RESPONSE_SIZE)
					.max_connections(config.max_connections)
					.build(),
			)
			.build(config.listen_addr)
			.await?;
		let local_addr = server.local_addr()?;
		log::info!("JSON-RPC server listening on {local_addr}");
		let handle = server.start(self.into_rpc());
		handle.stopped().await;
		Ok(())
	}
}

#[async_trait::async_trait]
impl RpcServer for Server {
	async fn logs(&self, service_id: ServiceId) -> RpcResult<Option<Vec<LogMessage>>> {
		Ok(self.logs.get(service_id))
	}

	async fn subscribe_logs(
		&self,
		pending: PendingSubscriptionSink,
		service_id: ServiceId,
	) -> SubscriptionResult {
		let sink = pending.accept().await?;
		if !self.logs.subscribe(service_id, sink) {
			return Err("Service not found".into());
		}
		Ok(())
	}
}
