<?php

declare(strict_types=1);

final class Session
{
    public const TYPE_INT = 1;
    public const TYPE_STRING = 2;
    public const TYPE_BOOL = 3;

    private const IS_LOGGED_IN = 'is_logged_in';
    private const USER_ID = 'account_id';
    private const USERNAME = 'username';
	private const PERMISSION = 'permission';
    private const EMAIL = 'email';
    private const JABBER_ADDRESS = 'jabber';

    public function __construct()
    {
        @session_start();

        if (!$this->HasValue(self::IS_LOGGED_IN)) {
            $this->SetBool(self::IS_LOGGED_IN, false);
        }
    }

    public function Destroy(): bool
    {
        return session_unset() && session_destroy();
    }

    public function Login(string $usernameOrEmail, string $password): bool
    {
        try {
            $user = User::getFromUsername($usernameOrEmail);
        } catch (Throwable $e) {
            $user = User::getFromEmail($usernameOrEmail);
        }

        if ($user === null || !Password::IsValid($password, $user->getPassword())) {
            return false;
        }

        $this->SetBool(self::IS_LOGGED_IN, true);
        $this->SetInt(self::USER_ID, $user->getPrimaryKey());
		$this->SetString(self::USERNAME, $user->getUsername());
        $this->SetString(self::EMAIL, $user->getEmail());
        $this->SetString(self::JABBER_ADDRESS, $user->getJabberAddress());

        return true;
    }

    public function HasValue(string $key): bool
    {
        return self::HasSession() && isset($_SESSION[$key]);
    }

    public function SetBool(string $key, bool $value): void
    {
        $_SESSION[$key] = $value;
    }

    public function SetString(string $key, string $value): void
    {
        $_SESSION[$key] = $value;
    }

    public function SetInt(string $key, int $value): void
    {
        $_SESSION[$key] = $value;
    }

    public function IsLoggedIn(): bool
    {
        return self::HasSession() && $this->GetBool(self::IS_LOGGED_IN);
    }

    public function GetInt(string $key): ?int
    {
        return $this->HasValue($key) ? (int)$_SESSION[$key] : null;
    }

    public function GetString(string $key): ?string
    {
        return $this->HasValue($key) ? (string)$_SESSION[$key] : null;
    }

    public function GetBool(string $key): ?bool
    {
        return $this->HasValue($key) ? (bool)$_SESSION[$key] : null;
    }

	public function GetAccountId(): ?int
	{
		return $this->GetInt(self::USER_ID);
	}

	public function GetPermission(): ?int
	{
		return $this->GetInt(self::PERMISSION);
	}

    public static function HasSession(): bool
    {
        return isset($_SESSION);
    }
}