<?php

declare(strict_types=1);

namespace App\Framework\Core;

use App\Framework\Cache\Cache;
use App\Framework\Config\Configuration;
use App\Framework\Core\Events\AfterEmitResponse;
use App\Framework\Core\Events\AfterHandleRequest;
use App\Framework\Core\Events\ApplicationBooted;
use App\Framework\Core\Events\BeforeEmitResponse;
use App\Framework\Core\Events\BeforeHandleRequest;
use App\Framework\Core\Events\EventCompilerPass;
use App\Framework\Core\Events\EventDispatcher;
use App\Framework\Core\Events\OnEvent;
use App\Framework\DI\DefaultContainer;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Http\MiddlewareManager;
use App\Framework\Http\Request;
use App\Framework\Http\ResponseEmitter;
use App\Framework\Router\HttpRouter;
use DateTimeImmutable;

final readonly class Application
{
    private MiddlewareManager $middlewareManager;
    private AttributeDiscoveryService $discoveryService;
    private EventDispatcher $eventDispatcher;

    public function __construct(
        private Container       $container,
        private PathProvider    $pathProvider,
        private ResponseEmitter $responseEmitter,
        private Configuration   $config
    ) {
        // Middleware-Manager initialisieren
        $this->middlewareManager = $this->container->get(MiddlewareManager::class);

        $this->eventDispatcher = $container->get(EventDispatcher::class);

        // Discovery-Service initialisieren
        #$this->discoveryService = new AttributeDiscoveryService($container, $pathProvider, $config);
    }

    /**
     * Führt die Anwendung aus
     */
    public function run(): void
    {
        // ApplicationBooted-Event dispatchen
        $environment = $this->config->get('environment', 'dev');
        $version = $this->config->get('app.version', 'dev');


        $bootEvent = new ApplicationBooted(
            new DateTimeImmutable(),
            $environment,
            $version
        );

        $this->event($bootEvent);

        // Attribute verarbeiten und Komponenten einrichten
        #$this->setupApplicationComponents();

        // Sicherstellen, dass ein Router registriert wurde
        if (!$this->container->has(HttpRouter::class)) {
            throw new \RuntimeException('Kritischer Fehler: Router wurde nicht initialisiert');
        }

        $this->event(new BeforeHandleRequest);


        $this->event(new AfterHandleRequest);

        $request = $this->container->get(Request::class);

        $response = $this->middlewareManager->chain->handle($request);

        $this->event(new BeforeEmitResponse);

        // Response ausgeben
        $this->responseEmitter->emit($response);

        $this->event(new AfterEmitResponse);
    }

    private function event(object $event): void
    {
        $this->eventDispatcher->dispatch($event);
    }


    /**
     * Gibt einen Konfigurationswert zurück
     */
    public function config(string $key, mixed $default = null): mixed
    {
        return $this->config->get($key, $default);
    }
}
