use serde::Deserialize;
use thiserror::Error;
use crate::{HomeAway, TeamSide};
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 __HomeOrAwayStruct<T: RawStat> {
	#[serde(flatten)]
	stats: WithSeason<T>,
	#[serde(rename = "isHome", deserialize_with = "crate::deserialize_team_side_from_is_home")]
	team_side: TeamSide,
}

pub type WithHomeAndAway<T> = HomeAway<WithSeason<T>>;

#[derive(Debug, Error)]
pub enum HomeAndAwayFromSplitWrappedVariantError {
	#[error("Did not find exactly two splits")]
	NotLen2,
	#[error("Found multiple home splits")]
	DuplicateHome,
	#[error("Found multiple away splits")]
	DuplicateAway,
}

impl<T: RawStat> Stat for WithHomeAndAway<T> {
	type Split = __HomeOrAwayStruct<T>;
	type TryFromSplitError = HomeAndAwayFromSplitWrappedVariantError;

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

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

		let mut split = Self {
			home: a.stats,
			away: b.stats,
		};

		if a.team_side.is_away() {
			split = split.swap();
		}

		Ok(split)
	}
}
