// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use serde::Serialize;
use tokio::io::{BufWriter, AsyncWriteExt};
use quinn::SendStream;

use super::super::{Error, QuicConnection, init::Writer, vu30::AsyncWriteVu30, super::serp};

pub struct Sender {
	stream: SenderInner,
	buf: Vec<u8>,
	conn: QuicConnection,
}

impl Sender {
	pub(super) fn new(stream: SendStream, conn: QuicConnection) -> Sender {
		Sender { stream: SenderInner(Some(BufWriter::new(stream))), buf: Vec::new(), conn }
	}

	/**
	 * Sends a message and flushes the stream.
	 */
	pub async fn send<M: Serialize>(&mut self, msg: &M) -> Result<(), Error> {
		self.send_unflushed(msg).await?;
		self.flush().await
	}

	async fn send_unflushed<M: Serialize>(&mut self, msg: &M) -> Result<(), Error> {
		self.buf.clear();
		serp::serialise_into(&mut self.buf, msg)?;
		self.stream.get().write_bytes(&self.buf).await.map_err(|err| err.into_error(&self.conn))
	}

	async fn flush(&mut self) -> Result<(), Error> {
		Ok(self.stream.get().flush().await.map_err(|_| &self.conn)?)
	}

	pub fn set_priority(&mut self, priority: i32) -> Result<(), Error> {
		Ok(self.stream.get().get_mut().set_priority(priority).map_err(|_| &self.conn)?)
	}

	pub async fn closed(&mut self) {
		let _ = self.stream.get().get_mut().stopped().await;
	}
}

impl Writer for Sender {
	async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
		Ok(self.stream.get().write_all(data).await.map_err(|_| &self.conn)?)
	}

	async fn write_and_flush(&mut self, data: &[u8]) -> Result<(), Error> {
		self.write(data).await?;
		self.flush().await
	}
}

pub struct SenderInner(Option<BufWriter<SendStream>>);

impl SenderInner {
	fn get(&mut self) -> &mut BufWriter<SendStream> {
		self.0.as_mut().unwrap()
	}
}

impl Drop for Sender {
	fn drop(&mut self) {
		let mut stream = self.stream.0.take().unwrap();
		tokio::spawn(async move { stream.get_mut().stopped().await });
	}
}
