use serde::Deserialize;
use std::num::NonZeroUsize;
use toolbox::{
	env::load_env,
	logging::{LogFilterPreset, LoggingFormat, LoggingInitializer, LoggingTarget, LokiConfig},
};
use tracing::info;

#[derive(Deserialize, Clone)]
pub struct WebpageConfig {
	#[serde(default)]
	pub loglevel: LogFilterPreset,

	#[serde(default)]
	pub logformat: LoggingFormat,

	#[serde(flatten)]
	pub loki: Option<LokiConfig>,

	// How many threads tokio should use
	pub runtime_threads: Option<NonZeroUsize>,
	pub blocking_threads: Option<NonZeroUsize>,
}

impl WebpageConfig {
	pub fn load() -> Self {
		let config_res = match load_env::<WebpageConfig>() {
			Ok(x) => x,

			#[expect(clippy::print_stdout)]
			Err(err) => {
				println!("Error while loading .env: {err}");
				std::process::exit(1);
			}
		};

		let config = config_res.get_config().clone();

		info!(message = "Config loaded");

		return config;
	}

	/*
	pub fn init_logging_noloki(&self) {
		let res = LoggingInitializer {
			app_name: "betalupi-webpage",
			loki: None,
			preset: self.loglevel,
			target: LoggingTarget::Stderr {
				format: self.logformat,
			},
		}
		.initialize();

		if let Err(e) = res {
			#[expect(clippy::print_stderr)]
			for e in e.chain() {
				eprintln!("{e}");
			}

			std::process::exit(1);
		}
	}
	*/

	/// Must be run inside a tokio context,
	/// use `init_logging_noloki` if you don't have async.
	pub async fn init_logging(&self) {
		let res = LoggingInitializer {
			app_name: "betalupi-webpage",
			loki: self.loki.clone(),
			preset: self.loglevel,
			target: LoggingTarget::Stderr {
				format: self.logformat,
			},
		}
		.initialize();

		if let Err(e) = res {
			#[expect(clippy::print_stderr)]
			for e in e.chain() {
				eprintln!("{e}");
			}

			std::process::exit(1);
		}
	}

	pub fn make_runtime(&self) -> tokio::runtime::Runtime {
		let mut rt = tokio::runtime::Builder::new_multi_thread();
		rt.enable_all();
		if let Some(threads) = self.runtime_threads {
			rt.worker_threads(threads.into());
		}

		if let Some(threads) = self.blocking_threads {
			rt.max_blocking_threads(threads.into());
		}

		#[expect(clippy::unwrap_used)]
		let rt = rt.build().unwrap();

		return rt;
	}
}
