<?php

declare(strict_types=1);

namespace Core;

use Throwable;

class Dispatcher
{
    protected Router $router;
    protected App $app;

    public function __construct(Router $router, App $app)
    {
        $this->router = $router;
        $this->app = $app;
    }

    public function dispatch(Request $request): Response
    {
        Request::setCurrent($request);

        try {
            $route = $this->router->match($request->method(), $request->path());

            if (!$route) {
                return Response::notFound('Page not found.');
            }

            $result = $route->dispatch($this->app);

            return $this->normalizeResponse($result);
        } catch (Throwable $e) {
            return Response::serverError($e->getMessage());
        } finally {
            Request::clearCurrent();
        }
    }

    protected function normalizeResponse(mixed $result): Response
    {
        if ($result instanceof Response) {
            return $result;
        }

        if (is_array($result)) {
            return Response::json($result);
        }

        return new Response((string) $result);
    }
}
