<?php

declare(strict_types=1);

namespace App\Framework\Config;

/**
 * Lightweight boot-time configuration validator.
 *
 * Non-invasive: reports issues via error_log and returns a list of problems
 * without throwing, so existing environments are not broken inadvertently.
 */
final readonly class ConfigValidator
{
    public function __construct(private Environment $env)
    {
    }

    /**
     * Validate selected environment variables and return a list of issues.
     * Each issue contains: key, issue, severity, recommendation.
     * @return array<int, array<string, string>>
     */
    public function validate(): array
    {
        /** @var array<int, array<string, string>> */
        $issues = [];

        // APP_ENV validation
        /** @var array<int, string> */
        $allowedEnvs = ['development', 'testing', 'production'];
        $appEnv = $this->env->getString(EnvKey::APP_ENV, 'production');
        if (! in_array($appEnv, $allowedEnvs, true)) {
            $issues[] = [
                'key' => 'APP_ENV',
                'issue' => 'invalid_value',
                'severity' => 'medium',
                'recommendation' => 'Setze APP_ENV auf einen der Werte: development | testing | production',
            ];
        }

        // APP_DEBUG should be boolean-like if present
        if ($this->env->has(EnvKey::APP_DEBUG)) {
            $raw = $this->env->get(EnvKey::APP_DEBUG);
            if (! is_bool($raw) && ! is_string($raw)) {
                $issues[] = [
                    'key' => 'APP_DEBUG',
                    'issue' => 'invalid_type',
                    'severity' => 'low',
                    'recommendation' => 'APP_DEBUG sollte true/false (oder "true"/"false") sein.',
                ];
            }
        }

        // APP_PORT if present should be a valid TCP port
        if ($this->env->has('APP_PORT')) {
            $port = (int) $this->env->get('APP_PORT');
            if ($port < 1 || $port > 65535) {
                $issues[] = [
                    'key' => 'APP_PORT',
                    'issue' => 'out_of_range',
                    'severity' => 'medium',
                    'recommendation' => 'APP_PORT muss zwischen 1 und 65535 liegen.',
                ];
            }
        }

        // Redis port if present
        if ($this->env->has('REDIS_PORT')) {
            $redisPort = (int) $this->env->get('REDIS_PORT');
            if ($redisPort < 1 || $redisPort > 65535) {
                $issues[] = [
                    'key' => 'REDIS_PORT',
                    'issue' => 'out_of_range',
                    'severity' => 'low',
                    'recommendation' => 'REDIS_PORT muss zwischen 1 und 65535 liegen.',
                ];
            }
        }

        // Rate limit values if present: must be non-negative
        /** @var array<int, string> */
        $rateKeys = [
            'RATE_LIMIT_DEFAULT',
            'RATE_LIMIT_WINDOW',
            'RATE_LIMIT_AUTH',
            'RATE_LIMIT_AUTH_WINDOW',
            'RATE_LIMIT_API',
            'RATE_LIMIT_API_WINDOW',
        ];
        foreach ($rateKeys as $rateKey) {
            if ($this->env->has($rateKey)) {
                $value = (int) $this->env->get($rateKey);
                if ($value < 0) {
                    $issues[] = [
                        'key' => $rateKey,
                        'issue' => 'negative_value',
                        'severity' => 'low',
                        'recommendation' => $rateKey . ' sollte eine nicht-negative Ganzzahl sein.',
                    ];
                }
            }
        }

        return $issues;
    }

    /**
     * Validate and log issues. Returns the list of issues for optional handling.
     * @return array<int, array<string, string>>
     */
    public function validateAndReport(): array
    {
        $issues = $this->validate();
        foreach ($issues as $issue) {
            $msg = sprintf(
                '[CONFIG] key=%s issue=%s severity=%s recommendation=%s',
                $issue['key'],
                $issue['issue'],
                $issue['severity'],
                $issue['recommendation']
            );
            error_log($msg);
        }

        return $issues;
    }
}
