<?php

/**
 * Persisted security settings (system_setting table in encrypted DB).
 */

function qdb_settings_defaults(): array
{
    return [
        'login_max_attempts'      => 10,
        'login_window_seconds'    => 900,
        'login_lockout_seconds'   => 900,
        'session_ttl_seconds'     => 30 * 24 * 60 * 60,
        'temp_session_ttl_seconds' => 10 * 60,
    ];
}

function qdb_settings_keys(): array
{
    return array_keys(qdb_settings_defaults());
}

function qdb_ensure_system_setting_table(PDO $pdo): void
{
    if (!qdb_table_exists($pdo, 'system_setting')) {
        $pdo->exec("
            CREATE TABLE system_setting (
                settingKey   TEXT NOT NULL PRIMARY KEY,
                settingValue TEXT NOT NULL DEFAULT ''
            )
        ");
    }
}

function qdb_settings_get_on_pdo(PDO $pdo): array
{
    qdb_ensure_system_setting_table($pdo);
    $out = qdb_settings_defaults();
    $rows = $pdo->query('SELECT settingKey, settingValue FROM system_setting')->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as $row) {
        $key = (string)($row['settingKey'] ?? '');
        if ($key === '' || !array_key_exists($key, $out)) {
            continue;
        }
        $out[$key] = (int)$row['settingValue'];
    }
    return $out;
}

function qdb_settings_get(): array
{
    require_once __DIR__ . '/../db_init.php';
    [$pdo, $tmpDb, $lockFp] = qdb_open(false);
    try {
        return qdb_settings_get_on_pdo($pdo);
    } finally {
        qdb_discard($tmpDb, $lockFp);
    }
}

/**
 * @param array<string, int> $partial
 * @param array<string, int>|null $base existing settings; defaults used when null
 * @return array<string, int> saved settings
 */
function qdb_settings_validate_and_merge(array $partial, ?array $base = null): array
{
    $merged = $base ?? qdb_settings_defaults();
    $limits = [
        'login_max_attempts'       => [1, 100],
        'login_window_seconds'     => [60, 86400],
        'login_lockout_seconds'    => [60, 86400],
        'session_ttl_seconds'      => [3600, 365 * 24 * 60 * 60],
        'temp_session_ttl_seconds' => [300, 24 * 60 * 60],
    ];
    foreach (qdb_settings_keys() as $key) {
        if (!array_key_exists($key, $partial)) {
            continue;
        }
        $val = (int)$partial[$key];
        [$min, $max] = $limits[$key];
        if ($val < $min || $val > $max) {
            throw new InvalidArgumentException(
                "$key must be between $min and $max"
            );
        }
        $merged[$key] = $val;
    }
    return $merged;
}

/**
 * @param array<string, int> $settings full merged settings to persist
 */
function qdb_settings_save_on_pdo(PDO $pdo, array $settings): void
{
    qdb_ensure_system_setting_table($pdo);
    $stmt = $pdo->prepare(
        'INSERT INTO system_setting (settingKey, settingValue)
         VALUES (:k, :v)
         ON CONFLICT(settingKey) DO UPDATE SET settingValue = excluded.settingValue'
    );
    foreach (qdb_settings_keys() as $key) {
        $stmt->execute([':k' => $key, ':v' => (string)(int)($settings[$key] ?? 0)]);
    }
}

function qdb_session_ttl_seconds(?array $settings = null, bool $temp = false): int
{
    $settings ??= qdb_settings_get();
    return $temp
        ? (int)$settings['temp_session_ttl_seconds']
        : (int)$settings['session_ttl_seconds'];
}
