<?php

declare(strict_types=1);

namespace App\Framework\Core;

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheInitializer;
use App\Framework\Config\Configuration;
use App\Framework\Config\Environment;
use App\Framework\Config\TypedConfigInitializer;
use App\Framework\Config\TypedConfiguration;
use App\Framework\Console\ConsoleApplication;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Context\ExecutionContext;
use App\Framework\DI\DefaultContainer;
use App\Framework\DI\Container;
use App\Framework\ErrorHandling\ErrorHandler;
use App\Framework\Http\ResponseEmitter;
use App\Framework\Performance\PerformanceCategory;
use App\Framework\Performance\PerformanceMeter;

/**
 * Verantwortlich für die grundlegende Initialisierung der Anwendung
 */
final readonly class AppBootstrapper
{
    private DefaultContainer $container;

    private ContainerBootstrapper $bootstrapper;

    public function __construct(
        private string           $basePath,
        private PerformanceMeter $meter,
        private array            $config = [],
    ){
        $this->container = new DefaultContainer();
        $this->bootstrapper = new ContainerBootstrapper($this->container);


        $env = Environment::fromFile($this->basePath . '/.env');

        $this->container->instance(TypedConfiguration::class, new TypedConfigInitializer($env)($this->container));


        // ExecutionContext detection sollte das erste sein, das nach dem Instanzieren des containers passiert. noch bevor dem bootstrap des containers.
        $executionContext = ExecutionContext::detect();
        $this->container->instance(ExecutionContext::class, $executionContext);

        error_log("AppBootstrapper: Context detected as {$executionContext->getType()->value}");
        error_log('AppBootstrapper: Context metadata: ' . json_encode($executionContext->getMetadata()));
    }

    public function bootstrapWeb(): Application
    {
        $this->bootstrap();
        $this->registerWebErrorHandler();
        $this->registerApplication();

        return $this->container->get(Application::class);
    }

    public function bootstrapConsole(): ConsoleApplication
    {
        $this->bootstrap();
        $this->registerCliErrorHandler();
        $this->registerConsoleApplication();

        return $this->container->get(ConsoleApplication::class);
    }

    public function bootstrapWorker(): Container
    {
        $this->bootstrap();
        $this->registerCliErrorHandler();

        $consoleOutput = new ConsoleOutput();
        $this->container->instance(ConsoleOutput::class, $consoleOutput);

        return $this->container;
    }

    private function bootstrap(): void
    {
        $this->meter->startMeasure('bootstrap:start', PerformanceCategory::SYSTEM);

        $this->bootstrapper->bootstrap($this->basePath, $this->meter, $this->config);

        // ErrorHandler wird jetzt kontextabhängig registriert
        // $this->container->get(ErrorHandler::class)->register();

        $this->meter->endMeasure('bootstrap:end');
    }

    private function registerWebErrorHandler(): void
    {
        $this->container->get(ErrorHandler::class)->register();
    }

    private function registerCliErrorHandler(): void
    {
        $output = $this->container->has(ConsoleOutput::class)
            ? $this->container->get(ConsoleOutput::class)
            : new ConsoleOutput();

        $cliErrorHandler = new \App\Framework\ErrorHandling\CliErrorHandler($output);
        $cliErrorHandler->register();
    }

    private function registerApplication(): void
    {
        $this->container->singleton(Application::class, function (Container $c) {
            return new Application(
                $c,
                $c->get(PathProvider::class),
                $c->get(ResponseEmitter::class),
                $c->get(Configuration::class)
            );
        });
    }

    private function registerConsoleApplication(): void
    {
        $this->container->singleton(ConsoleApplication::class, function (Container $c) {
            return new ConsoleApplication(
                $c,
                'console',
                'My Console App',
                null,
            );
        });
    }
}
