<?php

namespace apexl\Io\modules\user\services;

use apexl\ClassEngine\EngineSingleton;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\services\globalData;
use apexl\Io\services\Output;
use Firebase\JWT\JWT;
use Psr\Http\Message\ServerRequestInterface as Request;

class currentUser extends EngineSingleton
{
    public static function getCurrentUser(): ?userEntity
    {
        $entities = (globalData::getInstance())->getData('entities');
        return $entities['user']['entity'] ?? null;
    }

    /**
     * Create a JSON Web Token
     * @param $user
     * @param $sessionId
     * @param $secretKey
     * @param $algorithm
     * @param $lifetime
     * @return string
     */
    public static function createJWT($user, $sessionId, $secretKey, $algorithm, $lifetime)
    {
        $issuedAt   = new \DateTimeImmutable();
        $expire     = $issuedAt->modify("+$lifetime seconds")->getTimestamp();
        $serverName = $_SERVER['SERVER_NAME'];
        $payload = array(
            'userId' => $user->id,
            'sessionId' => $sessionId,
            'iat' => $issuedAt->getTimestamp(),
            'exp' => $expire,
            'nbf'  => $issuedAt->getTimestamp(),
            'iss' => $serverName
        );

        return JWT::encode($payload, $secretKey, $algorithm);
    }

    /**
     * Authenticate a JSON Web Token
     * @param $secretKey
     * @param $algorithm
     * @todo Review functionality; should probably throw an exception rather that return an array with an error
     */
    public static function authenticateJWT(Request $request, $secretKey, $algorithm): false|object|array
    {
        $error = null;
        if ($request->hasHeader('Authorization') && preg_match('/Bearer\s(\S+)/', $request->getHeader('Authorization')[0], $matches) && isset($matches[1])) {
            try {
                $token = JWT::decode($matches[1], $secretKey, [$algorithm]);
                $now = new \DateTimeImmutable();
                $serverName = $_SERVER['SERVER_NAME'];

                // Check token validity
                if ($token->iss === $serverName
                    && $token->nbf <= $now->getTimestamp() && $token->exp >= $now->getTimestamp()
                    && isset($token->sessionId) && !empty($token->sessionId)
                    && isset($token->userId) && $token->userId > 0) {
                    return [$token, $error];
                }
            } catch (\Exception $e) {
                $error = $e;
                // Output::addSystemError($e); - causing issues with 'AllowAll' permission - moved to session middleware
            }
        }

        return [false, $error];
    }

    /**
     * Get the current user ID from the Authorization header
     * @return null | object
     */
    public static function getClaimsFromJWT(Request $request)
    {
        if ($request->hasHeader('Authorization') && preg_match('/Bearer\s(\S+)/', $request->getHeader('Authorization')[0], $matches) && isset($matches[1])) {
            $parts = explode('.', $matches[1]);
            if (isset($parts[1])) {
                return json_decode(base64_decode($parts[1]));
            }
        }

        return null;
    }
}
