use std::collections::HashMap;

use serde::Deserialize;

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
pub struct Synthesis {
	pub sets: Vec<SynthesisSet>,
	pub recipes: Vec<SynthesisRecipe>,
}

impl Synthesis {
	pub fn new(path: &str) -> Synthesis {
		let str = std::fs::read_to_string(path).unwrap();
		let mut data = toml::from_str::<Synthesis>(&str).unwrap();

		for recipe in &mut data.recipes {
			for set in &data.sets {
				if set.id == recipe.set_id {
					recipe.set = set.clone();
					break;
				}
			}
		}

		data
	}

	pub fn total_amounts(&self) -> Vec<(String, u32)> {
		let mut map = HashMap::<String, u32>::new();
		self.recipes.iter().for_each(|recipe| {
			for item in &recipe.items {
				map.entry(item.name.clone())
					.and_modify(|val| *val += item.amount)
					.or_insert(0);
			}
		});

		let mut v = map.into_iter().collect::<Vec<_>>();
		v.sort_by(|a, b| b.1.cmp(&a.1));
		v
	}
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
pub struct SynthesisSet {
	pub id: u32,
	pub name: String,
	pub requirement: Option<String>,
}

impl PartialOrd for SynthesisSet {
	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
		Some(self.cmp(other))
	}
}

impl Ord for SynthesisSet {
	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
		self.id.cmp(&other.id)
	}
}

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct SynthesisRecipe {
	#[serde(rename = "set")]
	pub set_id: u32,
	#[serde(skip)]
	pub set: SynthesisSet,
	pub result: String,
	pub items: Vec<SynthesisRecipeItem>,
}

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct SynthesisRecipeItem {
	pub name: String,
	pub amount: u32,
}
