use std::fmt::Write as _;

pub async fn cmd_clean(
	global: &crate::Global,
	dry_run: bool,
) -> anyhow::Result<()> {
	#[derive(Debug,serde::Deserialize)]
	struct Sync {
		server_state: ServerState,
	}

	#[derive(Debug,serde::Deserialize)]
	struct ServerState {
		free_space_on_disk: u64,
	}

	let system = global.http.get(global.qbt.join("/api/v2/sync/maindata")?)
		.send().await?
		.error_for_status()?
		.json::<Sync>().await?;

	let Some(to_free) = global.config.target_free.checked_sub(system.server_state.free_space_on_disk)
		else {
			eprintln!(
				"Have {} free which satisfies target_free of {}, nothing to do.",
				crate::FmtBytes(system.server_state.free_space_on_disk),
				crate::FmtBytes(global.config.target_free));
			return Ok(())
		};

	eprintln!(
		"Going to free {} to hit target of {} free space.",
		crate::FmtBytes(to_free),
		crate::FmtBytes(global.config.target_free));

	let now = std::time::SystemTime::now();

	let mut groups = global.group(None).await?
		.filter(|g| g.pinned.is_none())
		.collect::<Vec<_>>();
	groups.sort_unstable_by_key(|g| {
		std::cmp::Reverse(crate::F64Ord(g.rank(&global)))
	});
	let mut groups = groups.into_iter();

	let mut removed_bytes = 0u64;
	let mut removed_groups = 0u64;
	let mut removed_torrents = 0u64;

	let mut hashes = String::new();
	for g in &mut groups {
		removed_bytes += g.content_size();
		removed_groups += 1;

		eprintln!(
			"--- group {}, torrents: {} ---",
			crate::FmtBytes(g.group_id()),
			g.torrents.len());

		for (i, t) in g.torrents.into_iter().enumerate() {
			let last_active = now.duration_since(t.last_activity)
				.unwrap_or(std::time::Duration::ZERO);

			eprintln!(
				"DELETE {} {:?} category: {}, tracker: {:?}, seeders: {}, active: {} ratio: {:.02}",
				t.hash,
				t.name,
				t.category,
				t.tracker_host().as_deref().unwrap_or(&t.tracker),
				t.seeders,
				crate::FmtDuration(last_active),
				t.ratio);

			if i == 0 {
				hashes.clear();
			} else {
				hashes.push('|');
			}
			write!(&mut hashes, "{}", t.hash)?;

			removed_torrents += 1;
		}

		if !dry_run {
			global.http.post(global.qbt.join("/api/v2/torrents/delete")?)
				.form(&[
					("deleteFiles", "true"),
					("hashes", &hashes),
				])
				.send().await?
				.error_for_status()?;
		}

		if removed_bytes >= to_free { break }
	}

	eprintln!(
		"Deleted {} torrents in {} groups. Aprox {} freed.",
		removed_torrents,
		removed_groups,
		crate::FmtBytes(removed_bytes));

	if to_free > removed_bytes {
		eprintln!("No more eligible torrents to reach free space target.");
	} else {
		let remaining = groups.map(|g| g.content_size()).sum();
		eprintln!("Free space target met. {} still available to clean.", crate::FmtBytes(remaining));
	}

	Ok(())
}
