use strafesnet_common::integer::{Ratio64,Ratio64Vec2};
#[derive(Clone)]
struct Ratio{
	ratio:f64,
}
#[derive(Clone)]
enum DerivedFov{
	FromScreenAspect,
	FromAspect(Ratio),
}
#[derive(Clone)]
enum Fov{
	Exactly{x:f64,y:f64},
	SpecifyXDeriveY{x:f64,y:DerivedFov},
	SpecifyYDeriveX{x:DerivedFov,y:f64},
}
impl Default for Fov{
	fn default()->Self{
		Fov::SpecifyYDeriveX{x:DerivedFov::FromScreenAspect,y:1.0}
	}
}
#[derive(Clone)]
enum DerivedSensitivity{
	FromRatio(Ratio64),
}
#[derive(Clone)]
enum Sensitivity{
	Exactly{x:Ratio64,y:Ratio64},
	SpecifyXDeriveY{x:Ratio64,y:DerivedSensitivity},
	SpecifyYDeriveX{x:DerivedSensitivity,y:Ratio64},
}
impl Default for Sensitivity{
	fn default()->Self{
		Sensitivity::SpecifyXDeriveY{x:Ratio64::ONE*524288,y:DerivedSensitivity::FromRatio(Ratio64::ONE)}
	}
}

#[derive(Default,Clone)]
pub struct UserSettings{
	fov:Fov,
	sensitivity:Sensitivity,
}
impl UserSettings{
	pub fn calculate_fov(&self,zoom:f64,screen_size:&glam::UVec2)->glam::DVec2{
		zoom*match &self.fov{
			&Fov::Exactly{x,y}=>glam::dvec2(x,y),
			Fov::SpecifyXDeriveY{x,y}=>match y{
				DerivedFov::FromScreenAspect=>glam::dvec2(*x,x*(screen_size.y as f64/screen_size.x as f64)),
				DerivedFov::FromAspect(ratio)=>glam::dvec2(*x,x*ratio.ratio),
			},
			Fov::SpecifyYDeriveX{x,y}=>match x{
				DerivedFov::FromScreenAspect=>glam::dvec2(y*(screen_size.x as f64/screen_size.y as f64),*y),
				DerivedFov::FromAspect(ratio)=>glam::dvec2(y*ratio.ratio,*y),
			},
		}
	}
	pub fn calculate_sensitivity(&self)->Ratio64Vec2{
		match &self.sensitivity{
			Sensitivity::Exactly{x,y}=>Ratio64Vec2::new(x.clone(),y.clone()),
			Sensitivity::SpecifyXDeriveY{x,y}=>match y{
				DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(x.clone(),x.mul_ref(ratio)),
			}
			Sensitivity::SpecifyYDeriveX{x,y}=>match x{
				DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(y.mul_ref(ratio),y.clone()),
			}
		}
	}
}

/*
//sensitivity is raw input dots (i.e. dpi = dots per inch) to radians conversion factor
sensitivity_x=0.001
sensitivity_y_from_x_ratio=1
Sensitivity::DeriveY{x:0.0.001,y:DerivedSensitivity{ratio:1.0}}
*/

pub fn read_user_settings()->UserSettings{
	let mut cfg=configparser::ini::Ini::new();
	if let Ok(_)=cfg.load("settings.conf"){
		let (cfg_fov_x,cfg_fov_y)=(cfg.getfloat("camera","fov_x"),cfg.getfloat("camera","fov_y"));
		let fov=match(cfg_fov_x,cfg_fov_y){
			(Ok(Some(fov_x)),Ok(Some(fov_y)))=>Fov::Exactly {
				x:fov_x,
				y:fov_y
			},
			(Ok(Some(fov_x)),Ok(None))=>Fov::SpecifyXDeriveY{
				x:fov_x,
				y:if let Ok(Some(fov_y_from_x_ratio))=cfg.getfloat("camera","fov_y_from_x_ratio"){
					DerivedFov::FromAspect(Ratio{ratio:fov_y_from_x_ratio})
				}else{
					DerivedFov::FromScreenAspect
				}
			},
			(Ok(None),Ok(Some(fov_y)))=>Fov::SpecifyYDeriveX{
				x:if let Ok(Some(fov_x_from_y_ratio))=cfg.getfloat("camera","fov_x_from_y_ratio"){
					DerivedFov::FromAspect(Ratio{ratio:fov_x_from_y_ratio})
				}else{
					DerivedFov::FromScreenAspect
				},
				y:fov_y,
			},
			_=>{
				Fov::default()
			},
		};
		let (cfg_sensitivity_x,cfg_sensitivity_y)=(cfg.getfloat("camera","sensitivity_x"),cfg.getfloat("camera","sensitivity_y"));
		let sensitivity=match(cfg_sensitivity_x,cfg_sensitivity_y){
			(Ok(Some(sensitivity_x)),Ok(Some(sensitivity_y)))=>Sensitivity::Exactly {
				x:Ratio64::try_from(sensitivity_x).unwrap(),
				y:Ratio64::try_from(sensitivity_y).unwrap(),
			},
			(Ok(Some(sensitivity_x)),Ok(None))=>Sensitivity::SpecifyXDeriveY{
				x:Ratio64::try_from(sensitivity_x).unwrap(),
				y:if let Ok(Some(sensitivity_y_from_x_ratio))=cfg.getfloat("camera","sensitivity_y_from_x_ratio"){
					DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_y_from_x_ratio).unwrap())
				}else{
					DerivedSensitivity::FromRatio(Ratio64::ONE)
				},
			},
			(Ok(None),Ok(Some(sensitivity_y)))=>Sensitivity::SpecifyYDeriveX{
				x:if let Ok(Some(sensitivity_x_from_y_ratio))=cfg.getfloat("camera","sensitivity_x_from_y_ratio"){
					DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_x_from_y_ratio).unwrap())
				}else{
					DerivedSensitivity::FromRatio(Ratio64::ONE)
				},
				y:Ratio64::try_from(sensitivity_y).unwrap(),
			},
			_=>{
				Sensitivity::default()
			},
		};
		UserSettings{
			fov,
			sensitivity,
		}
	}else{
		UserSettings::default()
	}
}