<?php

declare(strict_types=1);

namespace App\Framework\Config;

use App\Framework\Config\External\ExternalApiConfig;
use App\Framework\Database\Config\DatabaseConfig;
use App\Framework\Database\Config\DatabaseConfigInitializer;
use App\Framework\DateTime\Timezone;
use App\Framework\DI\Container;
use App\Framework\RateLimit\RateLimitConfig;

final readonly class TypedConfigInitializer
{
    public function __construct(
        private Environment $env,
    ) {
    }

    public function __invoke(Container $container): TypedConfiguration
    {
        $databaseConfig = $this->createDatabaseConfig();
        $appConfig = $this->createAppConfig();
        $securityConfig = $this->createSecurityConfig($appConfig->type);
        $rateLimitConfig = $this->createRateLimitConfig($securityConfig);
        $externalApiConfig = ExternalApiConfig::fromEnvironment($this->env);
        $discoveryConfig = DiscoveryConfig::fromEnvironment($this->env);

        $container->instance(DatabaseConfig::class, $databaseConfig);
        $container->instance(AppConfig::class, $appConfig);
        $container->instance(SecurityConfig::class, $securityConfig);
        $container->instance(RateLimitConfig::class, $rateLimitConfig);
        $container->instance(ExternalApiConfig::class, $externalApiConfig);
        $container->instance(DiscoveryConfig::class, $discoveryConfig);

        // Validate environment configuration (non-fatal reporting)
        $validator = new ConfigValidator($this->env);
        $validator->validateAndReport();

        return new TypedConfiguration(
            database: $databaseConfig,
            app: $appConfig,
            security: $securityConfig,
            rateLimit: $rateLimitConfig,
            externalApis: $externalApiConfig,
            discovery: $discoveryConfig,
        );
    }

    private function createAppConfig(): AppConfig
    {
        $environmentType = EnvironmentType::fromEnvironment($this->env);

        return new AppConfig(
            name: $this->env->getString(EnvKey::APP_NAME, 'Framework App'),
            version: $this->env->getString('APP_VERSION', '1.0.0'),
            environment: $this->env->getString(
                key: EnvKey::APP_ENV,
                default: 'production'
            ),
            debug: $this->env->getBool(EnvKey::APP_DEBUG, $environmentType->isDebugEnabled()),
            timezone: $this->env->getEnum(
                key: EnvKey::APP_TIMEZONE,
                enumClass: Timezone::class,
                default: Timezone::EuropeBerlin
            ),
            locale: $this->env->getString(EnvKey::APP_LOCALE, 'de'),
            type: $environmentType,
        );
    }

    private function createSecurityConfig(EnvironmentType $environmentType): SecurityConfig
    {
        return SecurityConfig::forEnvironment($environmentType, $this->env);
    }

    private function createDatabaseConfig(): DatabaseConfig
    {
        $initializer = new DatabaseConfigInitializer($this->env);

        return $initializer();
    }

    private function createRateLimitConfig(SecurityConfig $securityConfig): RateLimitConfig
    {
        return RateLimitConfig::fromSecurityConfig($securityConfig);
    }
}
