use serde::Serialize;
use std::ops::Not;

#[cfg(feature = "blocking")]
use crate::helpers::make_request_blocking;
use crate::{
	Result,
	helpers::make_request,
	pagination::Pagination,
	types::{MatchId, Season},
	user::identifier::UserIdentifier,
};

use super::{AdvancedMatchInfo, MatchInfo, MatchType};

impl AdvancedMatchInfo {
	pub async fn get_by_id(id: MatchId) -> Result<Self> {
		make_request!("https://api.mcsrranked.com/matches/{}"[id])
	}
}

#[cfg(feature = "blocking")]
impl AdvancedMatchInfo {
	pub fn get_by_id_blocking(id: MatchId) -> Result<Self> {
		make_request_blocking!("https://api.mcsrranked.com/matches/{}"[id])
	}
}

/// Parameters for [`UserIdentifier::get_user_matches`]
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
#[serde(rename_all = "lowercase")]
pub struct GetMatchesParams {
	#[serde(flatten)]
	pub pagination: Pagination,
	#[serde(rename = "type")]
	pub kind: Option<MatchType>,
	pub season: Option<Season>,
	pub exclude_decay: bool,
}
impl From<Pagination> for GetMatchesParams {
	fn from(pagination: Pagination) -> Self {
		Self {
			pagination,
			..Default::default()
		}
	}
}

impl<'a> UserIdentifier<'a> {
	/// GET the user's matches by identifier using given `params`
	pub async fn get_matches(
		&self,
		params: impl Into<Option<&'a GetMatchesParams>>,
	) -> Result<Box<[MatchInfo]>> {
		make_request!("https://api.mcsrranked.com/users/{}/matches" [self] params.into())
	}
}

#[cfg(feature = "blocking")]
impl<'a> UserIdentifier<'a> {
	/// Synchronously GET the user's matches by identifier using given `params`
	pub fn get_matches_blocking(
		&self,
		params: impl Into<Option<&'a GetMatchesParams>>,
	) -> Result<Box<[MatchInfo]>> {
		make_request_blocking!("https://api.mcsrranked.com/users/{}/matches" [self] params.into())
	}
}

/// Parameters for [`MatchInfo::get_recent`]
///
/// /// Note: this struct supports the builder pattern
///
/// # Examples
/// ```
/// use mcsr_ranked_api::game::requests::GetRecentMatchesParams;
/// use mcsr_ranked_api::game::MatchType;
/// let params = GetRecentMatchesParams::default()
///     .season(0)
///     .include_decay(true)
///     .kind(MatchType::Private);
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
#[serde(rename_all = "lowercase")]
pub struct GetRecentMatchesParams<'a> {
	#[serde(flatten)]
	pub pagination: Pagination,
	#[serde(rename = "type")]
	pub kind: Option<MatchType>,
	pub tag: Option<&'a str>,
	pub season: Option<Season>,
	#[serde(rename = "includedecay")]
	#[serde(skip_serializing_if = "Not::not")]
	pub include_decay: bool,
}
impl From<Pagination> for GetRecentMatchesParams<'_> {
	fn from(pagination: Pagination) -> Self {
		Self {
			pagination,
			..Default::default()
		}
	}
}
impl<'a> GetRecentMatchesParams<'a> {
	/// Set the `pagination` field
	///
	/// Note: it is better to use `From<Pagination>`
	pub fn pagination(mut self, pagination: Pagination) -> Self {
		self.pagination = pagination;
		self
	}
	/// Set the `kind` field
	pub fn kind(mut self, kind: MatchType) -> Self {
		self.kind = Some(kind);
		self
	}
	/// Set the `tag` field
	pub fn tag(mut self, tag: &'a str) -> Self {
		self.tag = Some(tag);
		self
	}
	/// Set the `season` field
	pub fn season(mut self, season: Season) -> Self {
		self.season = Some(season);
		self
	}
	/// Set the `include_decay` field
	pub fn include_decay(mut self, include_decay: bool) -> Self {
		self.include_decay = include_decay;
		self
	}
}

impl MatchInfo {
	/// GET recent matches given `params`
	pub async fn get_recent<'a>(
		params: impl Into<Option<&'a GetRecentMatchesParams<'a>>>,
	) -> Result<Box<[Self]>> {
		make_request!("https://api.mcsrranked.com/matches/" [] params.into())
	}
}

#[cfg(feature = "blocking")]
impl MatchInfo {
	/// Synchronously GET recent matches given `params`
	pub fn get_recent_blocking<'a>(
		params: impl Into<Option<&'a GetRecentMatchesParams<'a>>>,
	) -> Result<Box<[Self]>> {
		make_request_blocking!("https://api.mcsrranked.com/matches/" [] params.into())
	}
}
