<?php

namespace App\Services;

use App\Models\User;
use Firebase\JWT\JWT;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Cookie;

class JwtService
{
    /**
     * Generate a signed JWT for the given user.
     */
    public function generateToken(User $user): string
    {
        $now = time();
        $ttl = Config::get('jwt.ttl', 60);

        $payload = [
            'jti' => (string) str()->uuid(),
            'iss' => Config::get('jwt.issuer'),
            'aud' => Config::get('jwt.audience'),
            'iat' => $now,
            'nbf' => $now,
            'exp' => $now + ($ttl * 60),
            'sub' => (string) $user->id,
            'email' => $user->email,
            'ver' => (int) ($user->jwt_token_version ?? 1),
        ];

        $privateKey = Config::get('jwt.private_key');

        return JWT::encode($payload, $privateKey, 'RS256');
    }

    /**
     * Build an HTTP-only cookie that carries the JWT.
     */
    public function makeCookie(User $user): Cookie | false
    {
        if (!Config::get('jwt.private_key')) {
            return false;
        }

        $token = $this->generateToken($user);
        $ttl   = Config::get('jwt.ttl', 60);

        return new Cookie(
            name:     Config::get('jwt.cookie_name', 'wa_jwt'),
            value:    $token,
            expire:   time() + ($ttl * 60),
            path:     Config::get('jwt.cookie_path', '/'),
            domain:   Config::get('jwt.cookie_domain'),
            secure:   Config::get('jwt.cookie_secure', true),
            httpOnly: true,
            sameSite: Config::get('jwt.cookie_samesite', 'Lax'),
        );
    }

    /**
     * Rotate the user JWT version and return a new cookie.
     */
    public function makeRotatedCookie(User $user): Cookie | false
    {
        if (!Config::get('jwt.private_key')) {
            return false;
        }

        DB::transaction(function () use ($user): void {
            User::where('id', $user->id)->lockForUpdate()->increment('jwt_token_version');
            $user->refresh();
        });

        return $this->makeCookie($user);
    }

    /**
     * Build an expired cookie to clear the JWT on logout.
     */
    public function forgetCookie(): Cookie
    {
        return new Cookie(
            name:     Config::get('jwt.cookie_name', 'wa_jwt'),
            value:    '',
            expire:   time() - 3600,
            path:     Config::get('jwt.cookie_path', '/'),
            domain:   Config::get('jwt.cookie_domain'),
            secure:   Config::get('jwt.cookie_secure', true),
            httpOnly: true,
            sameSite: Config::get('jwt.cookie_samesite', 'Lax'),
        );
    }
}
