<?php

namespace apexl\Io\modules\user\services;

use apexl\Io\modules\user\entities\userEntity;
use DateTimeImmutable;
use Deprecated;
use Exception;
use Firebase\JWT\JWT;
use Psr\Http\Message\ServerRequestInterface as Request;
use function apexl\Io\container;

final readonly class currentUser
{
    #[Deprecated(message: 'Use apexl\\Io\\modules\\user\\services\\JwtCreator;
')]
    public static function createJWT(
        userEntity $user,
        string $sessionId,
        string $secretKey,
        string $algorithm,
        int $lifetime
    ): string {
        return container()->get(JwtCreator::class)->forUser($user, $sessionId);
    }

    /**
     * Authenticate a JSON Web Token
     * @todo Review functionality; should probably throw an exception rather that return an array with an error
     */
    public static function authenticateJWT(Request $request, string $secretKey, string $algorithm): false|object|array
    {
        $error = null;
        if (self::requestHasBearerAuthHeader($request, $matches)) {
            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;
            }
        }

        return [false, $error];
    }

    public static function requestHasBearerAuthHeader(Request $request, &$matches = []): bool
    {
        return self::requestHasAuthHeader($request, 'Bearer', $matches);
    }

    private static function requestHasAuthHeader(Request $request, string $type, &$matches = []): bool
    {
        $header = self::authHeader($request);
        $pattern = sprintf('/^%s\s(\S+)/', $type);

        return preg_match($pattern, $header, $matches);
    }

    private static function authHeader(Request $request): string
    {
        if ($request->hasHeader('Authorization')) {
            return $request->getHeader('Authorization')[0];
        }

        return '';
    }

    public static function getClaimsFromJWT(Request $request): ?object
    {
        if (self::requestHasBearerAuthHeader($request, $matches)) {
            [, $encodedToken] = $matches;

            return self::getSessionInfoFromToken($encodedToken);
        }

        return null;
    }

    private static function getSessionInfoFromToken(string $encodedToken): object
    {
        [, $encodedSessionInfo] = explode('.', $encodedToken);

        return json_decode(base64_decode($encodedSessionInfo));
    }

    public static function getTokenExpiryFromNow(string $encodedToken): int
    {
        $sessionInfo = self::getSessionInfoFromToken($encodedToken);

        return max($sessionInfo->exp - time(), 0);
    }

    public static function requestHasBasicAuthHeader(Request $request, &$matches = []): bool
    {
        return self::requestHasAuthHeader($request, 'Basic', $matches);
    }

}
