<?php
declare(strict_types=1);

namespace App\Middleware;

use Cake\Controller\Exception\MissingActionException;
use Cake\Http\Exception\MissingControllerException;
use Cake\Http\Exception\NotFoundException;
use Cake\Http\Response;
use Cake\Routing\Exception\MissingRouteException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class NotFoundRedirectMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        try {
            return $handler->handle($request);
        } catch (MissingRouteException | MissingControllerException | MissingActionException | NotFoundException $exception) {
            if (!$this->shouldRedirect($request)) {
                throw $exception;
            }

            $base = rtrim((string)$request->getAttribute('base'), '/');
            $target = sprintf(
                '%s/route-help?from=%s',
                $base,
                rawurlencode($request->getRequestTarget()),
            );

            return (new Response())
                ->withStatus(302)
                ->withHeader('Location', $target);
        }
    }

    private function shouldRedirect(ServerRequestInterface $request): bool
    {
        $method = strtoupper($request->getMethod());
        if (!in_array($method, ['GET', 'HEAD'], true)) {
            return false;
        }

        $acceptHeader = strtolower($request->getHeaderLine('Accept'));
        if (
            $acceptHeader !== ''
            && !str_contains($acceptHeader, 'text/html')
            && !str_contains($acceptHeader, '*/*')
        ) {
            return false;
        }

        $path = (string)$request->getUri()->getPath();
        if ($path === '/route-help' || str_ends_with($path, '/route-help')) {
            return false;
        }

        return preg_match('/\.[a-z0-9]{1,8}$/i', $path) !== 1;
    }
}
