<?php
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Router;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Mvc\Micro\MiddlewareInterface;
use Phalcon\Security;
use Phalcon\Flash\Direct as FlashDirect;
use \Firebase\JWT\JWT;


class AuthMiddleware implements MiddlewareInterface
{
    /**
     * Extract user and token from Authentication header if present
     */
    public function beforeExecuteRoute(Event $event, Micro $application)
    {
        $request = $application->request;
        $jwtPublicKey = $application->config['jwt_public_key'];
        $requestHeaders = $request->getHeaders();

        if (empty($jwtPublicKey)) {
            throw new CustomErrorException(BaseResponse::UNEXPECTED_ERROR, 'Server Config Error');
        }

        if (array_key_exists('Authorization', $requestHeaders) && strlen($requestHeaders['Authorization']) > 3) {
            $authorizationHeader = $requestHeaders['Authorization'];
            $authHeaders = explode(" ", $authorizationHeader);

            if (count($authHeaders) == 2 && $authHeaders[0] == 'Bearer') {
                $bearerToken = $authHeaders[1];

                try {
                    $jwt = JWT::decode($bearerToken, $jwtPublicKey, ['RS256']);
                } catch (\Firebase\JWT\ExpiredException $e) {
                    throw new CustomErrorException(BaseResponse::TOKEN_EXPIRED, 'Authentication token is expired');
                } catch (\Exception $e) {
                    throw new CustomErrorException(BaseResponse::INVALID_TOKEN_ERROR, 'Invalid JWT Token: ' . $e->getMessage());
                }

                $tokenData = JwtData::find(
                    [
                        "token = :token:",
                        "bind" => [
                            "token" => $jwt->jti
                        ]
                    ]
                );

                if (count($tokenData) < 1) {
                    throw new CustomErrorException(BaseResponse::TOKEN_NOT_FOUND, 'Authentication token not found');
                }

                if ($tokenData[0]->status == JwtData::STATUS_REVOKED)
                    throw new CustomErrorException(BaseResponse::TOKEN_EXPIRED, 'Authentication token is revoked');

                if ($jwt->exp < time()) {
                    throw new CustomErrorException(BaseResponse::TOKEN_EXPIRED, 'Authentication token is expired');
                }

                $users = UmUser::query()
                    ->where('email = :user_name:')
                    ->bind(['user_name' => $jwt->sub])
                    ->limit(1)
                    ->execute();

                if ($users->count() > 0) {
					if($users[0]->is_banned)
					{
						throw new CustomErrorException(BaseResponse::INVALID_TOKEN_ERROR, 'Token owner is banned');
					}
					else
					{
						$application->shared->user = $users[0];
						$application->shared->token = $tokenData;
						$application->shared->jwt = $jwt;
					}
                } else {
                    throw new CustomErrorException(BaseResponse::INVALID_TOKEN_ERROR, 'Token owner not found');
                }
            } else {
                throw new CustomErrorException(BaseResponse::INVALID_ACTION, 'Invalid authentication header');
            }
        }

        return true;
    }

    public function call(Micro $application)
    {
        return false;
    }
}
