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

use super::{SerialisedConfig, super::Filesystem};

pub struct ConfigSaveTask(Sender<Message>);

enum Message {
	Save(SerialisedConfig),
	Exit,
}

impl ConfigSaveTask {
	pub fn new(fs: Filesystem) -> ConfigSaveTask {
		let (sender, mut receiver) = mpsc::channel(16);
		tokio::spawn(async move {
			loop {
				match receiver.recv().await {
					Some(Message::Save(config)) => {
						if let Err(err) = config.save(&fs).await {
							log::warn!("cannot serialise config: {err}");
						}
					},
					Some(Message::Exit) => break,
					None => {
						log::warn!("dropped before calling `finish`, this shouldn't happen");
						break;
					},
				}
			}
		});
		ConfigSaveTask(sender)
	}

	pub fn save(&self, config: Option<SerialisedConfig>) {
		let Some(config) = config else { return; };

		if self.0.try_send(Message::Save(config)).is_err() {
			log::warn!("cannot push serialised config to save task, queue is full");
		}
	}

	pub async fn finish(self, final_config: Option<SerialisedConfig>) {
		if let Some(config) = final_config {
			let _ = self.0.send(Message::Save(config)).await;
		}
		if self.0.send(Message::Exit).await.is_err() {
			log::warn!("task closed before `finish`");
		}
		self.0.closed().await;
	}
}
