<?php

declare(strict_types=1);

namespace App\Framework\Router;

use App\Framework\Core\PathProvider;
use App\Framework\DI\DefaultContainer;
use App\Framework\Http\Headers;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Response;
use App\Framework\Http\Responses\SseResponse;
use App\Framework\Http\Responses\WebSocketResponse;
use App\Framework\Router\Result\FileResult;
use App\Framework\Router\Result\JsonResult;
use App\Framework\Router\Result\Redirect;
use App\Framework\Router\Result\SseResult;
use App\Framework\Router\Result\ViewResult;
use App\Framework\Router\Result\WebSocketResult;
use App\Framework\View\RenderContext;
use App\Framework\View\Template;
use App\Framework\View\TemplateRenderer;
use App\Framework\View\TemplateRendererInitializer;

final readonly class RouteResponder
{
    public function __construct(
        private PathProvider     $pathProvider,
        private DefaultContainer $container,
        private TemplateRenderer $templateRenderer,
    ) {}

    public function respond(Response|ActionResult $result): Response
    {
        if($result instanceof Response) {
            return $result;
        }

        return match(true) {
            $result instanceof ViewResult => new HttpResponse(
                status: $result->status,
                body: $this->renderTemplate(
                    new RenderContext(
                        template: $result->model ? $this->resolveTemplate($result->model) : $result->template,
                        metaData: $result->metaData,
                        data: $result->model ? get_object_vars($result->model) + $result->data : $result->data,
                        layout: '',
                        slots: $result->slots
                    )
                )
            ),
            $result instanceof JsonResult => new HttpResponse(
                status : $result->status,
                headers: new Headers()->with('Content-Type', 'application/json'),
                body   : json_encode($result->data),
            ),
            $result instanceof Redirect => new HttpResponse(
                status: $result->status,
                headers: new Headers()->with('Location', $result->target)
            ),
            $result instanceof SseResult => new SseResponse($result, $result->callback),
            $result instanceof WebSocketResult => $this->createWebSocketResponse($result),
            $result instanceof FileResult => new HttpResponse(
                #headers: new Headers()->with('Content-Type', $result->mimeType),
                body: $result->filePath
            ),

            default => throw new \RuntimeException('Unbekanntes Ergebnisobjekt: ' . get_class($result)),
        };
    }

    private function createWebSocketResponse(WebSocketResult $result): WebSocketResponse
    {
        // WebSocket-Key aus Request-Headers abrufen
        $websocketKey = $_SERVER['HTTP_SEC_WEBSOCKET_KEY'] ?? '';

        return new WebSocketResponse($result, $websocketKey);
    }

    private function renderTemplate(RenderContext $context): string
    {
        return $this->templateRenderer->render($context);
    }

    private function resolveTemplate(?object $model):string
    {
        if($model === null) {
            return 'test';
        }

        $ref = new \ReflectionClass($model);
        $attrs = $ref->getAttributes(Template::class);
        if ($attrs === []) {
            return 'test';
            #throw new \RuntimeException("Fehlendes #[Template] Attribut in {$ref->getName()}");
        }

        /** @var Template $attr */
        $attr = $attrs[0]->newInstance();
        return $attr->path;
    }
}
