use serde::Deserialize;
use thiserror::Error;
use crate::stats::{RawStat, Stat};
use crate::stats::wrappers::season::WithSeason;

#[derive(Debug, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(bound = "T: RawStat")]
#[doc(hidden)]
pub struct __WinOrLossStruct<T: RawStat> {
	#[serde(flatten)]
	stats: WithSeason<T>,
	is_win: bool,
}

#[derive(Debug, PartialEq, Clone, Default)]
pub struct WithWinLoss<T: RawStat> {
	pub win: WithSeason<T>,
	pub loss: WithSeason<T>,
}

#[derive(Debug, Error)]
pub enum WinLossFromSplitWrappedVariantError {
	#[error("Did not find exactly two splits")]
	NotLen2,
	#[error("Found multiple win splits")]
	DuplicateWin,
	#[error("Found multiple loss splits")]
	DuplicateLoss,
}

impl<T: RawStat> Stat for WithWinLoss<T> {
	type Split = __WinOrLossStruct<T>;
	type TryFromSplitError = WinLossFromSplitWrappedVariantError;

	fn from_splits(splits: impl Iterator<Item=Self::Split>) -> Result<Self, Self::TryFromSplitError>
	where
		Self: Sized
	{
		use WinLossFromSplitWrappedVariantError as Error;

		let [a, b] = <Vec<Self::Split> as TryInto<[Self::Split; 2]>>::try_into(splits.collect()).map_err(|_| Error::NotLen2)?;
		if a.is_win == b.is_win {
			return Err(if a.is_win { Error::DuplicateWin } else { Error::DuplicateLoss })
		}

		if a.is_win {
			Ok(Self {
				win: a.stats,
				loss: b.stats,
			})
		} else {
			Ok(Self {
				win: b.stats,
				loss: a.stats,
			})
		}
	}
}
