<?php
declare(strict_types=1);

namespace App\Core;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use App\Models\UserModel;
use App\Config\Database;
use Exception;

/**
 * JWT Auth Handler
 */
class Auth
{
    private static string $algo = 'HS256'; // Defaulting to HS256 for secret-based usage

    /**
     * Generate Access Token (15 min)
     */
    public static function generateAccessToken(int $userId, int $tenantId, string $role, array $permissions = []): string
    {
        $payload = [
            'iat' => time(),
            'exp' => time() + (int) ($_SERVER['JWT_EXPIRY'] ?? getenv('JWT_EXPIRY') ?: 900),
            'sub' => $userId,
            'tenant_id' => $tenantId,
            'role' => $role,
            'permissions' => $permissions ?? []
        ];
        return JWT::encode($payload, $_SERVER['JWT_SECRET'] ?? getenv('JWT_SECRET'), self::$algo);
    }

    /**
     * Generate Refresh Token (7 days)
     */
    public static function generateRefreshToken(int $userId): string
    {
        $token = bin2hex(random_bytes(32));
        $hash = hash('sha256', $token);
        $expiry = date('Y-m-d H:i:s', time() + (int) ($_SERVER['REFRESH_TOKEN_EXPIRY'] ?? getenv('REFRESH_TOKEN_EXPIRY') ?: 604800));

        $db = Database::getInstance();
        $stmt = $db->prepare("INSERT INTO refresh_tokens (user_id, token_hash, expires_at) VALUES (?, ?, ?)");
        $stmt->execute([$userId, $hash, $expiry]);

        return $token;
    }

    /**
     * Verify Access Token
     */
    public static function verifyAccessToken(string $token): ?array
    {
        try {
            $decoded = JWT::decode($token, new Key($_SERVER['JWT_SECRET'] ?? getenv('JWT_SECRET'), self::$algo));
            return (array) $decoded;
        } catch (Exception $e) {
            return null;
        }
    }

    public static function rotateRefreshToken(string $token): ?int
    {
        $db = Database::getInstance();
        $hash = hash('sha256', $token);
        
        $stmt = $db->prepare("SELECT id, user_id FROM refresh_tokens WHERE token_hash = ? AND expires_at > NOW() AND is_revoked = 0 LIMIT 1");
        $stmt->execute([$hash]);
        $record = $stmt->fetch();

        if ($record) {
            // Revoke Old
            $revokeStmt = $db->prepare("UPDATE refresh_tokens SET is_revoked = 1 WHERE id = ?");
            $revokeStmt->execute([$record['id']]);
            
            return (int) $record['user_id'];
        }
        
        return null;
    }

    /**
     * Revoke Refresh Token
     */
    public static function revokeRefreshToken(string $token): bool
    {
        $db = Database::getInstance();
        $hash = hash('sha256', $token);
        $stmt = $db->prepare("UPDATE refresh_tokens SET is_revoked = 1 WHERE token_hash = ?");
        return $stmt->execute([$hash]);
    }
}
