<?php

declare(strict_types=1);

namespace App\Infrastructure\Http\Middleware;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Validates `Authorization: Bearer <INTERNAL_JOB_TOKEN>` for `/internal/*`.
 * Uses `hash_equals` to avoid timing leaks. Mismatch returns 401 with the
 * same uniform error envelope used by the public token middleware.
 *
 * Network gate runs before this — by the time we get here, the source is
 * already trusted to be RFC1918/loopback.
 *
 * If `INTERNAL_JOB_TOKEN` is empty (the env var was forgotten), this
 * middleware refuses every request — better to fail closed than to expose
 * the endpoints unauthenticated to anything inside the docker network.
 */
final class InternalTokenMiddleware implements MiddlewareInterface
{
    public function __construct(
        private readonly ResponseFactoryInterface $responseFactory,
        private readonly string $expectedToken,
    ) {
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if ($this->expectedToken === '') {
            return $this->unauthorized();
        }

        $header = $request->getHeaderLine('Authorization');
        if ($header === '' || stripos($header, 'Bearer ') !== 0) {
            return $this->unauthorized();
        }

        $presented = trim(substr($header, 7));
        if (!hash_equals($this->expectedToken, $presented)) {
            return $this->unauthorized();
        }

        return $handler->handle($request);
    }

    private function unauthorized(): ResponseInterface
    {
        $response = $this->responseFactory->createResponse(401)
            ->withHeader('Content-Type', 'application/json');
        $response->getBody()->write((string) json_encode(['error' => 'unauthorized']));

        return $response;
    }
}
