<?php

declare(strict_types=1);

namespace BotGuard\Core;

/**
 * Configuration registry.
 *
 * Loads the `.env` file into the environment and lazily reads PHP config files
 * from the `config/` directory. Config values are addressed with dotted keys,
 * where the first segment is the file name, e.g. `config('database.host')`
 * reads the `host` key returned by `config/database.php`.
 */
final class Config
{
    /** @var array<string, array<string, mixed>> Loaded config files keyed by file name. */
    private static array $cache = [];

    private static string $configPath = '';

    private static bool $envLoaded = false;

    /**
     * Bootstrap configuration: load .env then remember where config files live.
     */
    public static function boot(string $basePath): void
    {
        self::$configPath = $basePath . DIRECTORY_SEPARATOR . 'config';
        self::loadEnv($basePath . DIRECTORY_SEPARATOR . '.env');
    }

    /**
     * Parse a `.env` file into $_ENV / $_SERVER / getenv().
     *
     * Supports `KEY=value`, comments (`#`), quoted values and blank lines.
     */
    public static function loadEnv(string $file): void
    {
        if (self::$envLoaded || ! is_file($file)) {
            self::$envLoaded = true;

            return;
        }

        $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];

        foreach ($lines as $line) {
            $line = trim($line);

            if ($line === '' || str_starts_with($line, '#') || ! str_contains($line, '=')) {
                continue;
            }

            [$key, $value] = explode('=', $line, 2);
            $key = trim($key);
            $value = trim($value);

            // Strip surrounding quotes if present.
            if (strlen($value) >= 2
                && (($value[0] === '"' && $value[-1] === '"') || ($value[0] === "'" && $value[-1] === "'"))) {
                $value = substr($value, 1, -1);
            }

            if ($key === '' || array_key_exists($key, $_ENV)) {
                continue;
            }

            $_ENV[$key] = $value;
            $_SERVER[$key] = $value;
            putenv("{$key}={$value}");
        }

        self::$envLoaded = true;
    }

    /**
     * Read a dotted config key with an optional default.
     */
    public static function get(string $key, mixed $default = null): mixed
    {
        $segments = explode('.', $key);
        $file = array_shift($segments);

        if (! isset(self::$cache[$file])) {
            self::$cache[$file] = self::loadFile($file);
        }

        $value = self::$cache[$file];

        foreach ($segments as $segment) {
            if (! is_array($value) || ! array_key_exists($segment, $value)) {
                return $default;
            }
            $value = $value[$segment];
        }

        return $value;
    }

    /**
     * Override a config value at runtime (used by tests).
     */
    public static function set(string $file, array $values): void
    {
        self::$cache[$file] = $values;
    }

    /**
     * @return array<string, mixed>
     */
    private static function loadFile(string $file): array
    {
        $path = self::$configPath . DIRECTORY_SEPARATOR . $file . '.php';

        if (! is_file($path)) {
            return [];
        }

        $data = require $path;

        return is_array($data) ? $data : [];
    }
}
