<?php
namespace App\Service;

class Auth
{
  protected $selector;
  protected $token;

  public function __construct()
  {
  	$this->getCookie();
  }
  protected function getCookie()
  {
    if (isset($_COOKIE['rememberMe'])) {
  		list($s, $t) = \explode(':', $_COOKIE['rememberMe']);
  		$this->selector = $s;
  		$this->token = $t;
  	}
  }
  protected function saveCookie()
  {
  	$now = \Carbon\Carbon::now(config('app.timezone'));
  	$exp = $now->addHours(config('app.login_hours'));
  	\setcookie('rememberMe', $this->selector . ':' . $this->token, $exp->timestamp);
  }
  protected function clearCookie()
  {
    \setcookie('rememberMe', '', \Carbon\Carbon::now(config('app.timezone'))->timestamp);
  }
  protected function generateToken()
  {
    $this->selector = bin2hex(\random_bytes(12));
    $this->token = bin2hex(\random_bytes(20));
  }
  public function login($username, $password)
  {
  	$user = \Model::factory(\Incoviba\common\User::class)->where('name', $username)->where('enabled', 1)->findOne();
  	if ($user !== false) {
  		if (\password_verify($password, $user->password) === false) {
        $this->clearCookie();
  			return false;
  		}

      $this->generateToken();
  		$now = \Carbon\Carbon::now(config('app.timezone'));
  		$exp = $now->addHours(-config('app.login_hours'));
  		$auth = \Model::factory(\Incoviba\common\Auth::class)->where('user_id', $user->id)->whereGt('time', $exp->timestamp)->where('status', 1)->findOne();
      if ($auth !== false) {
        $auth->time('now');
        $auth->selector = $this->selector;
  	  	$auth->token($this->token);
        $auth->save();
        $this->saveCookie();
  			return true;
  		}

	  	$auth = \Model::factory(\Incoviba\common\Auth::class)->create();
	  	$auth->user_id = $user->id;
	  	$auth->time('now');
	  	$auth->selector = $this->selector;
	  	$auth->token($this->token);

	  	try {
	  		$auth->save();
	  		$this->saveCookie();
	  		return true;
	  	} catch (\Exception $e) {
        $this->clearCookie();
	  		return false;
	  	}
  	}
  	return false;
  }
  public function isIn()
  {
  	if ($this->selector == null) {
  		return false;
  	}
  	$auths = \Model::factory(\Incoviba\common\Auth::class)->where('selector', $this->selector)->findMany();
  	if ($auths === false) {
      $this->clearCookie();
  		return false;
  	}
  	foreach ($auths as $auth) {
  		if (\password_verify($this->token, $auth->token)) {
  			return $auth->isIn();
  		}
  	}
  	return false;
  }
  public function User()
  {
  	if ($this->selector == null) {
  		return false;
  	}
  	$auths = \Model::factory(\Incoviba\common\Auth::class)->where('selector', $this->selector)->findMany();
  	if ($auths === false) {
  		return false;
  	}
  	foreach ($auths as $auth) {
  		if (\password_verify($this->token, $auth->token)) {
  			return $auth->user();
  		}
  	}
  	return false;
  }
  public function hasAccess()
  {
  	if ($this->selector == null) {
  		return false;
  	}
  	$auths = \Model::factory(\Incoviba\common\Auth::class)->where('selector', $this->selector)->findMany();
  	if ($auths === false) {
  		return false;
  	}
  	foreach ($auths as $auth) {
  		if (\password_verify($this->token, $auth->token)) {
  			return $auth->user()->hasAccess();
  		}
  	}
  	return false;
  }
  public function checkAccess($controller, $action = null)
  {
  	if ($this->selector == null) {
  		return false;
  	}
  	$auths = \Model::factory(\Incoviba\common\Auth::class)->where('selector', $this->selector)->findMany();
  	if ($auths === false) {
  		return false;
  	}
  	foreach ($auths as $auth) {
  		if (\password_verify($this->token, $auth->token)) {
  			return $auth->user()->checkAccess($controller, $action);
  		}
  	}
  	return false;
  }
  public function logout()
  {
    $this->clearCookie();
  	if ($this->selector == null) {
  		return true;
  	}
  	$auths = \Model::factory(\Incoviba\common\Auth::class)->where('selector', $this->selector)->findMany();
  	if ($auths === false) {
  		return true;
  	}
  	foreach ($auths as $auth) {
  		if (\password_verify($this->token, $auth->token)) {
		  	$auth->status = 0;
		  	try {
		  		$auth->save();
		  		return true;
		  	} catch (\Exception $e) {
		  		return false;
		  	}
  		}
  	}
  	return true;
  }
}
