use crate::timer::{TimerFixed,Realtime,Paused,Unpaused};
use crate::integer::Time;

#[derive(Clone,Debug)]
pub enum FlagReason{
	Anticheat,
	StyleChange,
	Clock,
	Pause,
	Flying,
	Gravity,
	Timescale,
	TimeTravel,
	Teleport,
}
impl ToString for FlagReason{
	fn to_string(&self)->String{
		match self{
			FlagReason::Anticheat=>"Passed through anticheat zone.",
			FlagReason::StyleChange=>"Changed style.",
			FlagReason::Clock=>"Incorrect clock.  (This can be caused by internet hiccups)",
			FlagReason::Pause=>"Pausing is not allowed in this style.",
			FlagReason::Flying=>"Flying is not allowed in this style.",
			FlagReason::Gravity=>"Gravity modification is not allowed in this style.",
			FlagReason::Timescale=>"Timescale is not allowed in this style.",
			FlagReason::TimeTravel=>"Time travel is not allowed in this style.",
			FlagReason::Teleport=>"Illegal teleport.",
		}.to_owned()
	}
}

#[derive(Debug)]
pub enum Error{
	NotStarted,
	AlreadyStarted,
	AlreadyFinished,
}
impl std::fmt::Display for Error{
	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
		write!(f,"{self:?}")
	}
}
impl std::error::Error for Error{}

#[derive(Clone,Debug)]
enum RunState{
	Created,
	Started{timer:TimerFixed<Realtime,Unpaused>},
	Finished{timer:TimerFixed<Realtime,Paused>},
}

#[derive(Clone,Debug)]
pub struct Run{
	state:RunState,
	flagged:Option<FlagReason>,
}

impl Run{
	pub fn new()->Self{
		Self{
			state:RunState::Created,
			flagged:None,
		}
	}
	pub fn time(&self,time:Time)->Time{
		match &self.state{
			RunState::Created=>Time::ZERO,
			RunState::Started{timer}=>timer.time(time),
			RunState::Finished{timer}=>timer.time(time),
		}
	}
	pub fn start(&mut self,time:Time)->Result<(),Error>{
		match &self.state{
			RunState::Created=>{
				self.state=RunState::Started{
					timer:TimerFixed::new(time,Time::ZERO),
				};
				Ok(())
			},
			RunState::Started{..}=>Err(Error::AlreadyStarted),
			RunState::Finished{..}=>Err(Error::AlreadyFinished),
		}
	}
	pub fn finish(&mut self,time:Time)->Result<(),Error>{
		//this uses Copy
		match &self.state{
			RunState::Created=>Err(Error::NotStarted),
			RunState::Started{timer}=>{
				self.state=RunState::Finished{
					timer:timer.into_paused(time),
				};
				Ok(())
			},
			RunState::Finished{..}=>Err(Error::AlreadyFinished),
		}
	}
	pub fn flag(&mut self,flag_reason:FlagReason){
		//don't replace the first reason the run was flagged
		if self.flagged.is_none(){
			self.flagged=Some(flag_reason);
		}
	}
}