<?php

declare(strict_types=1);

namespace App\Model;

use Nette\Security as NS;
use Exception;
use Nette\Database\UniqueConstraintViolationException;
use Nette\Security\AuthenticationException;
use Nette\Security\IAuthenticator;
use Nette\Security\Identity;
use Nette\Security\Passwords;
use Nette\Database\Context;


class UserManager extends DatabaseManager implements IAuthenticator {

	private $passwords;

	const
		#DB
		TABLE_NAME = 'users',
		COLUMN_ID = 'user_id',
		COLUMN_NAME = 'name',
		COLUMN_PASSWORD_HASH = 'pass',
		COLUMN_ROLE = 'role';

	private $name;
	private $pass;
	
	public function __construct(Context $database, Passwords $passwords)
	{
		$this->database = $database;
		$this->passwords = $passwords;
	}

	public function authenticate(array $credentials): NS\IIdentity {

		list($username, $password) = $credentials; 

		$user = $this->database->table(self::TABLE_NAME)->where(self::COLUMN_NAME, $username)->fetch();

		if (!$user) { 
			throw new AuthenticationException('Uživatel neexistuje.', self::IDENTITY_NOT_FOUND);
		} elseif (!$this->passwords->verify($password, $user[self::COLUMN_PASSWORD_HASH])) { 
			throw new AuthenticationException('Zadané heslo není správné.', self::INVALID_CREDENTIAL);
		} elseif ($this->passwords->needsRehash($user[self::COLUMN_PASSWORD_HASH])) {
			$user->update([self::COLUMN_PASSWORD_HASH => $this->passwords->hash($password)]);
		}

		$userAttributes = $user->toArray(); 
		unset($userAttributes[self::COLUMN_PASSWORD_HASH]); 

		return new Identity($user[self::COLUMN_ID], $user[self::COLUMN_ROLE], $userAttributes);
		
	}

	public function register($username, $password) {

		try {
			$this->database->table(self::TABLE_NAME)->insert([
				self::COLUMN_NAME => $username,
				self::COLUMN_PASSWORD_HASH => $this->passwords->hash($password)
			]);
		} catch (UniqueConstraintViolationException $e) {
			throw new DuplicateNameException;
		}
	}

	#uprava hesla
	public function save($values, $overeni) {

		$this->name = $values->username;

		if ($this->name == $overeni) 
		{
			$this->pass = $this->passwords->hash($values->password);
			$this->database->table(self::TABLE_NAME)->where(self::COLUMN_NAME, $this->name)->update(array('pass' => $this->pass));
		} 
	}

	public function getUsers() {

		return $this->database->table(self::TABLE_NAME)->order(self::COLUMN_ID . ' DESC');
	}

	public function removeUser($id) {
		$this->database->table(self::TABLE_NAME)->where(self::COLUMN_ID, $id)->delete();
	}

	public function zmenitOpravneni($id) {
		$values = array (
			'role' => 'admin',
		);
		$this->database->table(self::TABLE_NAME)->where(self::COLUMN_ID, $id)->update($values);
	}

}

#anti duplicita
class DuplicateNameException extends Exception {
	protected $message = 'Uživatel s tímto uživatelským jménem je již zaregistrován.';
}
