<?php

declare(strict_types=1);

namespace App\Framework\Http\Session;

use App\Framework\Context\ContextType;
use App\Framework\Core\Events\EventDispatcher;
use App\Framework\DateTime\Clock;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Http\ResponseManipulator;
use App\Framework\Random\RandomGenerator;
use App\Framework\Random\SecureRandomGenerator;
use App\Framework\Redis\RedisConfig;
use App\Framework\Redis\RedisConnection;
use App\Framework\Security\CsrfTokenGenerator;

final readonly class SessionInitializer
{
    public function __construct(
        private Container $container
    ) {
    }

    #[Initializer(ContextType::WEB)]
    public function __invoke(): SessionManager
    {
        return $this->createSessionManager();
    }

    private function createSessionManager(): SessionManager
    {
        $clock = $this->container->get(Clock::class);
        #$csrfTokenGenerator = $this->container->get(CsrfTokenGenerator::class);
        $randomGenerator = new SecureRandomGenerator();
        #$randomGenerator = $this->container->get(RandomGenerator::class);

        $sessionIdGenerator = new SimpleSessionIdGenerator($randomGenerator);
        $csrfTokenGenerator = new CsrfTokenGenerator($randomGenerator);

        // Create session storage
        try {
            // Check if Redis extension is available
            if (! extension_loaded('redis')) {
                throw new \RuntimeException('Redis extension not loaded');
            }

            $redisConfig = new RedisConfig(host: 'redis', database: 3);
            $redisConnection = new RedisConnection($redisConfig, 'session');
            $storage = new RedisSessionStorage($redisConnection);
        } catch (\Throwable $e) {
            // Fallback to file-based storage if Redis is not available
            $storage = new FileSessionStorage();
        }

        // Session Fingerprinting konfigurieren
        $fingerprintConfig = SessionFingerprintConfig::fromEnvironment();
        $fingerprint = new SessionFingerprint($fingerprintConfig);

        // EventDispatcher optional laden
        $eventDispatcher = null;
        if ($this->container->has(EventDispatcher::class)) {
            $eventDispatcher = $this->container->get(EventDispatcher::class);
        }

        // Cookie-Konfiguration basierend auf Umgebung
        $isProduction = ($_ENV['APP_ENV'] ?? 'development') === 'production';
        $cookieConfig = $isProduction
            ? SessionCookieConfig::forProduction()
            : SessionCookieConfig::forDevelopment();

        return new SessionManager(
            $sessionIdGenerator,
            new ResponseManipulator(),
            $clock,
            $csrfTokenGenerator,
            $storage,
            $cookieConfig,
            $fingerprint,
            $eventDispatcher
        );
    }
}
