<?php

declare(strict_types=1);

namespace App\Services;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use App\Models\Session;
use App\Models\User;
use Ramsey\Uuid\Uuid;

class JwtService
{
    private string $secret;
    private int $expiry;
    private int $refreshExpiry;

    public function __construct()
    {
        $this->secret       = $_ENV['JWT_SECRET'] ?? '';
        $this->expiry       = (int)($_ENV['JWT_EXPIRY'] ?? 86400);
        $this->refreshExpiry = (int)($_ENV['JWT_REFRESH_EXPIRY'] ?? 2592000);
    }

    public function generateAccessToken(int $userId, string $role, ?int $atelierId = null): string
    {
        $payload = [
            'iss'       => $_ENV['APP_URL'] ?? 'https://api.mykollector.com',
            'iat'       => time(),
            'exp'       => time() + $this->expiry,
            'sub'       => (string)$userId,
            'role'      => $role,
            'atelier_id'=> $atelierId,
        ];
        return JWT::encode($payload, $this->secret, 'HS256');
    }

    public function generateRefreshToken(int $userId, string $ip = '', string $userAgent = ''): string
    {
        $token = Uuid::uuid4()->toString();
        $expiresAt = date('Y-m-d H:i:s', time() + $this->refreshExpiry);

        Session::create([
            'user_id'       => $userId,
            'refresh_token' => $token,
            'expires_at'    => $expiresAt,
            'ip'            => $ip,
            'user_agent'    => $userAgent,
        ]);

        return $token;
    }

    public function verifyAccessToken(string $token): ?object
    {
        try {
            return JWT::decode($token, new Key($this->secret, 'HS256'));
        } catch (\Exception $e) {
            return null;
        }
    }

    public function refreshAccessToken(string $refreshToken): ?array
    {
        $session = Session::where('refresh_token', $refreshToken)
            ->where('expires_at', '>', date('Y-m-d H:i:s'))
            ->first();

        if (!$session) {
            return null;
        }

        $user = User::find($session->user_id);
        if (!$user || !$user->actif) {
            return null;
        }

        // Rotation : révoquer l'ancien, créer un nouveau
        $session->delete();
        $newRefresh = $this->generateRefreshToken($user->id);
        $newAccess  = $this->generateAccessToken($user->id, $user->role, $user->atelier_id);

        return [
            'token'         => $newAccess,
            'refresh_token' => $newRefresh,
        ];
    }

    public function revokeRefreshToken(string $refreshToken): void
    {
        Session::where('refresh_token', $refreshToken)->delete();
    }

    public function extractFromRequest(\Psr\Http\Message\ServerRequestInterface $request): ?object
    {
        // Lecture standard du header Authorization
        $header = $request->getHeaderLine('Authorization');

        // Fallback OVH : Apache mutualisé supprime Authorization
        // — récupéré via RewriteRule E=HTTP_AUTHORIZATION ou SetEnvIf
        if (!$header) {
            $header = $_SERVER['HTTP_AUTHORIZATION']
                   ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION']
                   ?? '';
        }

        if (preg_match('/Bearer\s+(.+)/i', $header, $matches)) {
            return $this->verifyAccessToken(trim($matches[1]));
        }
        return null;
    }

    public function getUserFromRequest(\Psr\Http\Message\ServerRequestInterface $request): ?User
    {
        $payload = $this->extractFromRequest($request);
        if (!$payload) {
            return null;
        }
        return User::find((int)$payload->sub);
    }
}
