<?php

app_require('traits/module_config_variable_t.php');

use traits\module_config_variable;

function selfserve_module_config_database_config(): array
{
    $subject = new class {
        use module_config_variable;
    };

    $method = new ReflectionMethod($subject::class, 'readDatabaseConfigFromEnvironment');

    return $method->invoke(null);
}

function selfserve_module_config_with_env(array $values, callable $callback): mixed
{
    $keys = [
        'CONFIG_DB_TARGET',
        'CONFIG_DB_HOST',
        'CONFIG_DB_USER',
        'CONFIG_DB_PASSWORD',
        'CONFIG_DB_DATABASE',
        'CONFIG_DB_PORT',
        'CONFIG_DB_SSL_MODE',
        'CONFIG_DB_DEBUG_HOST',
        'CONFIG_DB_DEBUG_USER',
        'CONFIG_DB_DEBUG_PASSWORD',
        'CONFIG_DB_DEBUG_DATABASE',
        'CONFIG_DB_DEBUG_PORT',
        'CONFIG_DB_DEBUG_SSL_MODE',
    ];
    $previous = [];

    foreach ($keys as $key) {
        $previous[$key] = [
            'env' => getenv($key),
            'has_env' => array_key_exists($key, $_ENV),
            'super_env' => $_ENV[$key] ?? null,
            'has_server' => array_key_exists($key, $_SERVER),
            'server' => $_SERVER[$key] ?? null,
        ];
        putenv($key);
        unset($_ENV[$key], $_SERVER[$key]);
    }

    try {
        foreach ($values as $key => $value) {
            putenv($key . '=' . (string)$value);
            $_ENV[$key] = (string)$value;
            $_SERVER[$key] = (string)$value;
        }

        return $callback();
    } finally {
        foreach ($previous as $key => $state) {
            $state['env'] === false
                ? putenv($key)
                : putenv($key . '=' . $state['env']);

            if ($state['has_env']) {
                $_ENV[$key] = $state['super_env'];
            } else {
                unset($_ENV[$key]);
            }

            if ($state['has_server']) {
                $_SERVER[$key] = $state['server'];
            } else {
                unset($_SERVER[$key]);
            }
        }
    }
}

it('reads debug database configuration when the debug target is selected', function (): void {
    $config = selfserve_module_config_with_env([
        'CONFIG_DB_TARGET' => 'debug',
        'CONFIG_DB_HOST' => '',
        'CONFIG_DB_USER' => '',
        'CONFIG_DB_PASSWORD' => '',
        'CONFIG_DB_DATABASE' => '',
        'CONFIG_DB_PORT' => '',
        'CONFIG_DB_SSL_MODE' => '',
        'CONFIG_DB_DEBUG_HOST' => 'mysql-debug',
        'CONFIG_DB_DEBUG_USER' => 'root',
        'CONFIG_DB_DEBUG_PASSWORD' => 'debug_root_password',
        'CONFIG_DB_DEBUG_DATABASE' => 'nnks_db_debug',
        'CONFIG_DB_DEBUG_PORT' => '3306',
        'CONFIG_DB_DEBUG_SSL_MODE' => 'DISABLED',
    ], static fn(): array => selfserve_module_config_database_config());

    expect($config)->toMatchArray([
        'host' => 'mysql-debug',
        'user' => 'root',
        'password' => 'debug_root_password',
        'database' => 'nnks_db_debug',
        'port' => 3306,
        'ssl_mode' => 'DISABLED',
    ]);
});

it('keeps live database configuration as the default target', function (): void {
    $config = selfserve_module_config_with_env([
        'CONFIG_DB_HOST' => 'live-db',
        'CONFIG_DB_USER' => 'live-user',
        'CONFIG_DB_PASSWORD' => 'live-password',
        'CONFIG_DB_DATABASE' => 'live-database',
        'CONFIG_DB_PORT' => '3307',
        'CONFIG_DB_SSL_MODE' => 'REQUIRED',
        'CONFIG_DB_DEBUG_HOST' => 'mysql-debug',
        'CONFIG_DB_DEBUG_USER' => 'root',
        'CONFIG_DB_DEBUG_PASSWORD' => 'debug_root_password',
        'CONFIG_DB_DEBUG_DATABASE' => 'nnks_db_debug',
        'CONFIG_DB_DEBUG_PORT' => '3306',
        'CONFIG_DB_DEBUG_SSL_MODE' => 'DISABLED',
    ], static fn(): array => selfserve_module_config_database_config());

    expect($config)->toMatchArray([
        'host' => 'live-db',
        'user' => 'live-user',
        'password' => 'live-password',
        'database' => 'live-database',
        'port' => 3307,
        'ssl_mode' => 'REQUIRED',
    ]);
});
