<?php

declare(strict_types=1);

namespace App\Application\Admin;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
 * `GET /api/v1/admin/config` — effective config the api is using,
 * with secrets masked.
 *
 * Masking rules per SPEC §M12.5:
 *  - `***`               for: INTERNAL_JOB_TOKEN, MAXMIND_LICENSE_KEY,
 *                            IPINFO_TOKEN, DB_MYSQL_PASSWORD
 *  - first 8 + `...`     for: UI_SERVICE_TOKEN
 *  - plain values        for everything else
 *
 * Returns config grouped by section so the UI can render it without
 * inventing categorisation. RBAC: Admin only — viewers and operators
 * see no_access.
 */
final class ConfigController
{
    use AdminControllerSupport;

    /**
     * @param array<string, mixed> $settings Effective settings array (the same array that built the container).
     */
    public function __construct(private readonly array $settings)
    {
    }

    public function show(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        return self::json($response, 200, [
            'sections' => $this->sections(),
        ]);
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function sections(): array
    {
        $db = $this->settings['db'] ?? [];
        $geoip = $this->settings['geoip'] ?? [];

        return [
            'app' => [
                'APP_ENV' => $this->settings['app_env'] ?? null,
                'LOG_LEVEL' => $this->levelName(),
                'UI_ORIGIN' => $this->settings['ui_origin'] ?? null,
            ],
            'database' => [
                'DB_DRIVER' => $db['driver'] ?? null,
                'DB_SQLITE_PATH' => $db['sqlite_path'] ?? null,
                'DB_MYSQL_HOST' => $db['mysql_host'] ?? null,
                'DB_MYSQL_PORT' => $db['mysql_port'] ?? null,
                'DB_MYSQL_DATABASE' => $db['mysql_database'] ?? null,
                'DB_MYSQL_USERNAME' => $db['mysql_username'] ?? null,
                'DB_MYSQL_PASSWORD' => self::mask((string) ($db['mysql_password'] ?? '')),
            ],
            'auth' => [
                'UI_SERVICE_TOKEN' => self::previewToken((string) ($this->settings['ui_service_token'] ?? '')),
                'INTERNAL_JOB_TOKEN' => self::mask((string) ($this->settings['internal_job_token'] ?? '')),
                'OIDC_DEFAULT_ROLE' => $this->oidcDefaultRoleName(),
            ],
            'reputation' => [
                'SCORE_REPORT_HARD_CUTOFF_DAYS' => $this->settings['score_hard_cutoff_days'] ?? null,
                'SCORE_RECOMPUTE_INTERVAL_SECONDS' => $this->settings['score_recompute_interval_seconds'] ?? null,
                'API_RATE_LIMIT_PER_SECOND' => $this->settings['rate_limit_per_second'] ?? null,
                'CIDR_EVALUATOR_TTL_SECONDS' => $this->settings['cidr_evaluator_ttl_seconds'] ?? null,
                'BLOCKLIST_CACHE_TTL_SECONDS' => $this->settings['blocklist_cache_ttl_seconds'] ?? null,
            ],
            'jobs' => [
                'JOB_RECOMPUTE_MAX_RUNTIME_SECONDS' => $this->settings['job_recompute_max_runtime_seconds'] ?? null,
                'JOB_RECOMPUTE_MAX_ROWS_PER_TICK' => $this->settings['job_recompute_max_rows_per_tick'] ?? null,
                'JOB_AUDIT_RETENTION_DAYS' => $this->settings['job_audit_retention_days'] ?? null,
                'JOB_GEOIP_REFRESH_INTERVAL_DAYS' => $geoip['refresh_interval_days'] ?? null,
            ],
            'geoip' => [
                'GEOIP_ENABLED' => $geoip['enabled'] ?? null,
                'GEOIP_PROVIDER' => $geoip['provider'] ?? null,
                'GEOIP_COUNTRY_DB' => $geoip['country_db'] ?? null,
                'GEOIP_ASN_DB' => $geoip['asn_db'] ?? null,
                'MAXMIND_LICENSE_KEY' => self::mask((string) ($geoip['maxmind_license_key'] ?? '')),
                'IPINFO_TOKEN' => self::mask((string) ($geoip['ipinfo_token'] ?? '')),
            ],
        ];
    }

    private static function mask(string $value): string
    {
        return $value === '' ? '' : '***';
    }

    /**
     * Token preview: empty stays empty so misconfiguration is visible;
     * present values show first 8 + ellipsis.
     */
    private static function previewToken(string $value): string
    {
        if ($value === '') {
            return '';
        }

        return substr($value, 0, 8) . '...';
    }

    private function levelName(): ?string
    {
        $level = $this->settings['log_level'] ?? null;
        if ($level instanceof \Monolog\Level) {
            return $level->getName();
        }

        return is_string($level) ? $level : null;
    }

    private function oidcDefaultRoleName(): ?string
    {
        $role = $this->settings['oidc_default_role'] ?? null;
        if ($role === null) {
            return 'none';
        }
        if ($role instanceof \App\Domain\Auth\Role) {
            return $role->value;
        }

        return is_string($role) ? $role : null;
    }
}
