use crate::types::*;

#[derive(Clone)]
pub struct Context(crate::context::Context);

impl Context{
	pub fn new(base_url:String,cookie:crate::context::Cookie)->reqwest::Result<Self>{
		Ok(Self(crate::context::Context::new(base_url,Some(cookie))?))
	}
	pub async fn get_script(&self,config:GetScriptRequest)->Result<ScriptResponse,Error>{
		let url_raw=format!("{}/scripts/{}",self.0.base_url,config.ScriptID.0);
		let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		response_ok(
			self.0.get(url).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?
		.json().await.map_err(Error::Reqwest)
	}
	pub async fn get_scripts<'a>(&self,config:GetScriptsRequest<'a>)->Result<Vec<ScriptResponse>,Error>{
		let url_raw=format!("{}/scripts",self.0.base_url);
		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		{
			let mut query_pairs=url.query_pairs_mut();
			query_pairs.append_pair("Page",config.Page.to_string().as_str());
			query_pairs.append_pair("Limit",config.Limit.to_string().as_str());
			if let Some(name)=config.Name{
				query_pairs.append_pair("Name",name);
			}
			if let Some(hash)=config.Hash{
				query_pairs.append_pair("Hash",hash);
			}
			if let Some(source)=config.Source{
				query_pairs.append_pair("Source",source);
			}
			if let Some(submission_id)=config.SubmissionID{
				query_pairs.append_pair("SubmissionID",submission_id.to_string().as_str());
			}
		}

		response_ok(
			self.0.get(url).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?
		.json().await.map_err(Error::Reqwest)
	}
	pub async fn get_script_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptResponse>,SingleItemError>{
		let scripts=self.get_scripts(GetScriptsRequest{
			Page:1,
			Limit:2,
			Hash:Some(config.hash),
			Name:None,
			Source:None,
			SubmissionID:None,
		}).await.map_err(SingleItemError::Other)?;
		if 1<scripts.len(){
			return Err(SingleItemError::DuplicateItems);
		}
		Ok(scripts.into_iter().next())
	}
	pub async fn create_script<'a>(&self,config:CreateScriptRequest<'a>)->Result<ScriptIDResponse,Error>{
		let url_raw=format!("{}/scripts",self.0.base_url);
		let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		let body=serde_json::to_string(&config).map_err(Error::JSON)?;

		response_ok(
			self.0.post(url,body).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?
		.json().await.map_err(Error::Reqwest)
	}
	pub async fn get_script_policies<'a>(&self,config:GetScriptPoliciesRequest<'a>)->Result<Vec<ScriptPolicyResponse>,Error>{
		let url_raw=format!("{}/script-policy",self.0.base_url);
		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		{
			let mut query_pairs=url.query_pairs_mut();
			query_pairs.append_pair("Page",config.Page.to_string().as_str());
			query_pairs.append_pair("Limit",config.Limit.to_string().as_str());
			if let Some(hash)=config.FromScriptHash{
				query_pairs.append_pair("FromScriptHash",hash);
			}
			if let Some(script_id)=config.ToScriptID{
				query_pairs.append_pair("ToScriptID",script_id.0.to_string().as_str());
			}
			if let Some(policy)=config.Policy{
				query_pairs.append_pair("Policy",(policy as i32).to_string().as_str());
			}
		}

		response_ok(
			self.0.get(url).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?
		.json().await.map_err(Error::Reqwest)
	}
	pub async fn get_script_policy_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptPolicyResponse>,SingleItemError>{
		let policies=self.get_script_policies(GetScriptPoliciesRequest{
			Page:1,
			Limit:2,
			FromScriptHash:Some(config.hash),
			ToScriptID:None,
			Policy:None,
		}).await.map_err(SingleItemError::Other)?;
		if 1<policies.len(){
			return Err(SingleItemError::DuplicateItems);
		}
		Ok(policies.into_iter().next())
	}
	pub async fn create_script_policy(&self,config:CreateScriptPolicyRequest)->Result<ScriptPolicyIDResponse,Error>{
		let url_raw=format!("{}/script-policy",self.0.base_url);
		let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		let body=serde_json::to_string(&config).map_err(Error::JSON)?;

		response_ok(
			self.0.post(url,body).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?
		.json().await.map_err(Error::Reqwest)
	}
	pub async fn update_script_policy(&self,config:UpdateScriptPolicyRequest)->Result<(),Error>{
		let url_raw=format!("{}/script-policy/{}",self.0.base_url,config.ID.0);
		let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;

		let body=serde_json::to_string(&config).map_err(Error::JSON)?;

		response_ok(
			self.0.post(url,body).await.map_err(Error::Reqwest)?
		).await.map_err(Error::Response)?;

		Ok(())
	}
}