<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class JwtAuth
{
    public function handle(Request $request, Closure $next): Response
    {
        $token = $this->extractToken($request);

        if (! $token) {
            return response()->json([
                'message' => 'Authentication required',
            ], 401);
        }

        $payload = $this->decodeJWT($token);

        if (! $payload) {
            return response()->json([
                'message' => 'Invalid token',
            ], 401);
        }

        if ($payload->exp < time()) {
            return response()->json([
                'message' => 'Token expired',
            ], 401);
        }

        $user = \App\Models\User::find($payload->sub);

        if (! $user) {
            return response()->json([
                'message' => 'User not found',
            ], 401);
        }

        auth()->setUser($user);
        $request->setUserResolver(fn () => $user);

        return $next($request);
    }

    protected function extractToken(Request $request): ?string
    {
        $header = $request->header('Authorization');

        if (! $header || ! str_starts_with($header, 'Bearer ')) {
            return null;
        }

        return substr($header, 7);
    }

    protected function decodeJWT(string $token): ?object
    {
        $parts = explode('.', $token);

        if (count($parts) !== 3) {
            return null;
        }

        list($header, $payload, $signature) = $parts;

        $expectedSignature = hash_hmac('sha256', $header . '.' . $payload, config('app.key'), true);
        $expectedSignature = base64_encode($expectedSignature);
        $expectedSignature = str_replace(['+', '/', '='], ['-', '_', ''], $expectedSignature);

        if (! hash_equals($expectedSignature, $signature)) {
            return null;
        }

        $payload = base64_decode(str_replace(['-', '_'], ['+', '/'], $payload));

        return json_decode($payload);
    }
}
