<?php 
// namespace controllers;
// use core\view as View;
// use helpers\url as Url; //may be omitted
// use core\auth as Auth;
// use helpers\session as Session;

/**
* Login Controller
* Controls the login processes and procedures
*/
class Login extends Controller{
	/**
	* Construct this object by extending the basic Controller class
	*/
	// private $_login_model;
	function __construct(){
		parent::__construct();
		// $this->_login_model = $this->loadModel('login_model');
		// $this->_login_model = new login_m();
		Language::load();
		$this->loadModel('login');
	}

	/**
	* Login default action to allow user to login with any type , NO RENDER
	* NOTE: This both is the actual login action with remember me
	* @param mix POST
	* @return appropriate Feedback 
	**/
	public function login(){
		/* check for "Cooked" login upon success redirection to dashboard... */
		if(Auth::handleCookedLogin()){
			Url::redirect('profile/index');
		}
		/* create a login model to perform the getFacebookLoginUrl() method */
		/* if we use Facebook: this is necessary as we need the facebook_login_url in the login form (in the view) */
		//if(FACEBOOK_LOGIN == true) {
			/* Need more reconfigurations */
		//	$this->_view->facebook_login_url = $login_model->getFacebookLoginUrl();
		//}
		/* get any posting if user begin to enter email and password */
		/* NOTE : Add in future suspend for 3 failed attempts under current session/ip  */
		$p_user_email = @filter_var($_POST['user_email'], FILTER_SANITIZE_EMAIL);
		$p_user_password = @filter_var($_POST['user_password'], FILTER_SANITIZE_STRING);
		/* simple check for emptiness and length */ 
		if(!empty($p_user_email) AND !empty($p_user_password)){
			if(strlen($p_user_password) >= 4 AND strlen($p_user_password) <= 64){
				/* NOTE : for this POST i'm ignoring if nothing is posted */
				$p_user_rememberme = filter_var(@$_POST['user_rememberme'], FILTER_SANITIZE_NUMBER_INT);
				/* run the login() method in the login-model, put the result in $login_successful (true or false) */
				/* perform the login method, put result (true or false) into $login_successful */
				$login_successful = $this->_model->get_Login($p_user_email,$p_user_password,$p_user_rememberme);
				if($login_successful){
					/* Collect this information on every request */
					$adressip = "";//@$_SERVER['REMOTE_ADDR'];
					$browserip = @$_SERVER['HTTP_X_FORWARDED_FOR'];
					$agent = @$_SERVER['HTTP_USER_AGENT'];
					/* set users confirmation for successful login on session identity */
					Session::set('user_ident',hash("sha1", USER_TOKEN.$adressip.$agent.$browserip));
					Session::set("user_logged_in",true);
					/* if YES, then move user to dashboard/index (BTW. this is a browser-redirection, not a rendered view!) */
					// Url::redirect('dashboard/index');
					echo 'SUCCESS';
					return;
				}
			}
			//$data = 'The email or password you entered is incorrect.';
			/* get last error from session if such exists */
			if(Session::get("feedback_negative"))
				echo Session::pull("feedback_negative");
			else
				echo 'LOGIN_FAILED';
			return;
		}
		/** if nothing to POST the user shouldn't see that page any way **/
		Url::redirect('');
	}

	/**
	* The logout action, login/logout
	* Redirects to landing page
	**/
	public function logout(){
		$this->_model->set_Logout();
		/* redirect user to base URL */
		Url::redirect('');
	}

	/**
	* Register page, will show registration form
	* May be need the Facebook-register-URL for Facebook acount registration
	**/
	public function register(){
		// if we use Facebook: this is necessary as we need the facebook_register_url in the login form (in the view)
		//if(FACEBOOK_LOGIN == true) {
			//$data['facebook_register_url'] = $this->_login_model->getFacebookRegisterUrl();
		//	$data['facebook_register_url'] = $this->_model->get_FacebookRegisterUrl();
		//}
		// If it's a registered user he cannot register once again !!!
		if(Auth::handleCookedLogin())
			Url::redirect('');
		$this->_view->rendercusttmpl('orn','header');
		$this->_view->render('guest/top');
		$this->_view->render('login/register');
		$this->_view->render('guest/bottom');
		$this->_view->rendercusttmpl('orn','footer');
	}

	/**
	* Register page action for form submiting , NO RENDER
	* @params mix POST
	* @return STRING status messages...
	*/
	public function register_action(){
		$reg_success=false;
		/* First step sensitization... empty string will result in FALSE */
		$p_user_gender = (int)filter_var($_POST['user_gender'], FILTER_SANITIZE_NUMBER_INT);
		$p_user_birth = filter_var($_POST['user_birth'], FILTER_SANITIZE_NUMBER_FLOAT);
		$p_user_email = filter_var($_POST['user_email'], FILTER_SANITIZE_EMAIL);
		$p_user_name = filter_var($_POST['user_name'], FILTER_SANITIZE_STRING);
		$p_user_password = filter_var($_POST['user_password'], FILTER_SANITIZE_STRING);
		$p_user_password_rep = filter_var($_POST['user_password_rep'], FILTER_SANITIZE_STRING);
		$p_user_captcha = filter_var($_POST['user_captcha'], FILTER_SANITIZE_STRING);
		$date_check = DateTime::createFromFormat("Y-m-d",$p_user_birth);
		if(empty($p_user_birth) OR empty($p_user_email) OR empty($p_user_password) OR empty($p_user_password_rep) OR empty($p_user_captcha)  OR empty($p_user_name)){
			return;
		}else if($p_user_captcha != $_SESSION['captcha']){
			echo 'CAPTCHA_WRONG';
			return;
		}else if($p_user_password != $p_user_password_rep){
			echo 'PASSWORD_NOT_MATCH';
			return;
		}else if(strlen($p_user_password) <= 3){
			echo 'PASSWORD_WRONG';
			return;
		}else if(strlen($p_user_name) <= 3){
			echo 'NAME_WRONG';
			return;
		}else if(!filter_var($p_user_email, FILTER_VALIDATE_EMAIL)){
			echo 'EMAIL_WRONG';
			return;
		}else if($p_user_gender != 1 AND $p_user_gender != 2){
			echo 'GENDER_WRONG';
			return;
		// }else if(date_parse($p_user_birth)['warning_count'] != 0){
			// echo 'false - date';
			// return;
		}else if($date_check === false OR array_sum($date_check->getLastErrors())){
			echo 'DATE_WRONG';
			return;
		}else if((new \DateTime("NOW"))->diff($date_check)->format("%y") <= 17){
			echo 'DATE_YOUNG';
			return;
		}else{
			// Seems like input is OK lets try to create instance in DB
			$reg_success = $this->_model->set_RegisterNewUser($p_user_name,$p_user_gender,$p_user_birth,$p_user_email,$p_user_password);
		}
		// Success return entire array in order to compose and send email to user if such not work we 
		// have to proceed and delete new account from DB for trying re-create the account according to email
		if($reg_success){
			/* Compose and send email to newly created account to active it */
			// It's better to get the return in case of send if failed
			$this->mail_ActivateLink($reg_success->user_id,$reg_success->user_email,$reg_success->user_activation_hash);
			/* will echo on success the return path */
			echo 'SUCCESS';
			return;
		}else{
			return;
		}
	}

	/**
	* Compose and send verification mail with New Account Activation link to newly created user
	* @param INT user id, STRING email, STRING activation hash
	* @return BOOL for successfully send mail or failure
	*/
	public function mail_ActivateLink($user_id,$user_mail,$user_activation_hash){
		/* render mail content with user information */
		$data=['user_id'=>$user_id,'user_mail'=>$user_mail,'user_activation_hash'=>$user_activation_hash];
		ob_start();
		$this->_view->renderPath('mails/login/verify',$data);
		$content = ob_get_clean();
		try{
			$mail = new Mailer();
			$mail->setSender(SITETITLE, EMAIL_NO_REPLY.EMAIL_ADDRESS);
			$mail->setReplyTo(SITETITLE, EMAIL_INFO.EMAIL_ADDRESS);
			$mail->addRecipient("User ID : ".$user_id,$user_mail);
			$mail->setSubject(Language::getValue('mail_acnt_actv'));
			$mail->setMessage($content);
			$mail->send();
		}catch(Exception $e){
			error_log($e->getMessage());
			return false;
		}
		return true;
	}

	/**
	* Verify user after activation mail link opened NOT verified (OR Baned )user will not shown is search result!
	* @param INT $user_id user's id
	* @param STRING $user_activation_verification_code user's verification token
	**/
	public function verify($user_id,$user_activation_verification_code){
		/* This is more for brute force... may be implemented in model itself for check after sanitation */
		// UNCOMENT IN REAL SITE !!! because in the mail you should set the email itself !!!
		// $is_email = filter_var($_GET['user_email'],FILTER_VALIDATE_EMAIL);
		// if(!$is_email)
		// Url::redirect('login/index');
		$user_activation_verification_code = filter_var($user_activation_verification_code, FILTER_SANITIZE_STRING);
		$user_id = filter_var($user_id, FILTER_SANITIZE_NUMBER_INT);
		if(!empty($user_id) && !empty($user_activation_verification_code)){
			$data = $this->_model->get_NewUserVerify($user_id, $user_activation_verification_code);
			if($data)
				$data = Language::getValue('acnt_ver_suces');
			else
				$data = Language::getValue('acnt_ver_fail');
			View::rendercusttmpl('orn','header');
			View::render('login/verify',$data);
			View::rendercusttmpl('orn','footer');
		}else{
			Url::redirect('');
		}
	}


	/**
	* Changing password with a new one, please note that this happens only when the user is logged in.
	* Don't forget to perform the necessary actions to send a password change mail ?
	* @param STRING POST for all passwords...
	* @return STRING with statuses
	**/
	public function changePassword(){
		if(!Auth::handleCookedLogin()){
			Url::redirect('');
			return;
		}
		/* Sanitize POST vars */
		$p_change_pass_old = filter_var($_POST['change_pass_old'], FILTER_SANITIZE_STRING);
		$p_change_pass_new = filter_var($_POST['change_pass_new'], FILTER_SANITIZE_STRING);
		$p_change_pass_rep = filter_var($_POST['change_pass_rep'], FILTER_SANITIZE_STRING);
		/* Simple checks CSRF will be used, needs more consideration! */
		if(strlen($p_change_pass_old) >= 64 OR strlen($p_change_pass_old) <= 4 OR
			strlen($p_change_pass_new) >= 64 OR strlen($p_change_pass_new) <= 4 OR
			strlen($p_change_pass_rep) >= 64 OR strlen($p_change_pass_rep) <= 4){
			echo 'PASSWORD_SHORT';
			return;
		}
		if($p_change_pass_new != $p_change_pass_rep){
			echo 'PASSWORD_NOT_MATCH';
			return;
		}
		/* continue POSTing only email get BOOL result for existing email */
		$data = $this->_model->set_PasswordChange(Session::get('user_id'),Session::get('user_email'),$p_change_pass_old,$p_change_pass_rep);
		/* don't forget to add email sending !!! (when on server) */
		if($data)
			echo 'SUCCESS';
		else
			echo Session::pull("feedback_negative");
		return;
	}


	/**
	* Request for forgotten password restoration threw email , NO RENDER
	* Don't forget to perform the necessary actions to send a password reset mail
	* @param STRING MAIL 
	* @return STRING success status
	**/
	public function forgotPassword(){
		// Sanitize and check email
		$p_user_email = filter_var($_POST['user_email'], FILTER_VALIDATE_EMAIL);
		$p_forgot_captcha = filter_var($_POST['forgot_captcha'], FILTER_SANITIZE_STRING);
		// Simple checks CSRF will be used, needs more consideration!
		if(strlen($p_user_email) >= 64 OR strlen($p_user_email) <= 6 OR strlen($p_forgot_captcha) >= 7 OR strlen($p_forgot_captcha) <= 3){
			echo 'ERROR_UNKNOWN';//.strlen($p_user_email);
			return;
		}
		// the session is without a prefix it's important to remember :) i love myself
		if($_SESSION['captcha'] == $p_forgot_captcha){
			// continue POSTing only email get bool result for existing email
			$data = $this->_model->set_PasswordForgot($p_user_email);
			// don't forget to add email sending !!! (when on server)
			if($data)
				$this->mail_PasswordForgot($data->user_id,$p_user_email,$data->user_password_reset_hash);
			// I always return true because user should not know if such email is registered on my server
			echo 'EMAIL_CHECK';
			return;
		}
		// default error wrong captcha
		echo 'CAPTCHA_WRONG';
		return;
	}

	/**
	* Compose and send verification mail with New Account Activation link to newly created user in DB
	* @param INT user id, STRING MAIL and activation hash 
	* @return BOOL for successfully send mail or failure
	*/
	public function mail_PasswordForgot($user_id,$user_mail,$user_activation_hash){
		/* render mail content with user information */
		$data=['user_id'=>$user_id,'user_mail'=>$user_mail,'user_activation_hash'=>$user_activation_hash];
		ob_start();
		$this->_view->renderPath('mails/login/passForgot',$data);
		$content = ob_get_clean();
		try{
			$mail = new Mailer();
			$mail->setSender(SITETITLE, EMAIL_NO_REPLY.EMAIL_ADDRESS);
			$mail->setReplyTo(SITETITLE, EMAIL_INFO.EMAIL_ADDRESS);
			$mail->addRecipient("User ID : ".$user_id,$user_mail);
			$mail->setSubject(Language::getValue('pass_rest'));
			$mail->setMessage($content);
			$mail->send();
		}catch(Exception $e){
			error_log($e->getMessage());
			return false;
		}
		return true;
	}


	/**
	* Password reset link was requested if such exists and true user forgot his password i'll check for valid combination and time window fitting
	* If the link is true will check for self posting a new password and successful change of it
	* NOTE this method both receives the actual link for check and self POSTing
	* @params INT for user id and STRING for activation hash
	* @params POST new password and repeated one 
	**/
	public function passwordReset($userId,$userHash){
		/* This is more for brute force... may be implemented in model itself for check after sanitation */
		// UNCOMENT IN REAL SITE !!! because in the mail you should set the email itself !!!
		// $is_email = filter_var($_GET['user_email'],FILTER_VALIDATE_EMAIL);
		// if(!$is_email)
		// Url::redirect('');
		if(isset($userId) && isset($userHash)){
			$userHash = filter_var($userHash, FILTER_SANITIZE_STRING);
			$userId = filter_var($userId, FILTER_SANITIZE_NUMBER_INT);
			/* request such combination in DB and get for success the user hash */
			$data = $this->_model->get_VerifyPasswordReset($userId,$userHash);
			if(sizeof($data) >= 1){
				/* Sanitize POST vars if such was send and begin pass forgot procedure */
				$p_change_pass_new = filter_var($_POST['change_pass_new'], FILTER_SANITIZE_STRING);
				$p_change_pass_rep = filter_var($_POST['change_pass_rep'], FILTER_SANITIZE_STRING);
				/* check if user landed first time or already posting new password */
				if(!empty($p_change_pass_new) && !empty($p_change_pass_rep)){
					/* Simple checks CSRF will be used, needs more consideration! */
					if(strlen($p_change_pass_new) >= 64 OR strlen($p_change_pass_new) <= 4 OR
						strlen($p_change_pass_rep) >= 64 OR strlen($p_change_pass_rep) <= 4){
						echo 'PASSWORD_SHORT';
						return;
					}
					if($p_change_pass_new != $p_change_pass_rep){
						echo 'PASSWORD_NOT_MATCH';
						return;
					}
					// try to call function with updating db and return success or failure need to think of UI / UX 
					// crypt the new password
					$p_change_pass_new = crypt($p_change_pass_rep, BLOWFISH_HASH_COST.$data->user_creation_hash_salt);
					// try to set a new password for user
					$query_u = $this->_model->get_PasswordReset($userId,$p_change_pass_new);
					// just return success or some unknown error to user
					if($query_u)
						echo 'SUCCESS';
					else
						echo 'ERROR_RETRY';
					return;
				}
				// Just show the input for new password field and return messages...
				View::rendercusttmpl('orn','header');
				View::render('login/passforgot');
				View::rendercusttmpl('orn','footer');
			}else{
			error_log('login pass request5 :'.$data);
				Url::redirect('');
			}
		}else{
			Url::redirect('');
		}
	}

}