<?php
// =============================================================================
// /api/webview_settings.php — generic key/value store used by every WebViews
// admin page that doesn't need its own table:
//   - TMDB Settings (tmdb_api_key, metadata_language, feed_type, region,
//                    original_audio_languages, mix_movies_tv, block_adult,
//                    cert_cap, min_vote_count, block_list)
//   - TMDB Layouts (tmdb_layout_style, tmdb_slide_interval, tmdb_accent_color,
//                   tmdb_visibility_title|year|genre|vote|overview|...)
//   - Sports per-source widget (sports_widget_<source>, sports_external_url)
//   - QR Settings (qr_* — see api/qr_settings.php for the schema)
//
// GET  ?keys=key1,key2,...    → {key1:'v', key2:'v', ...}     (only listed)
// GET                          → { all rows }                  (admin only)
// POST { key,value } pairs    → upsert all
// =============================================================================
require_once __DIR__ . '/_common.php';
require_csrf_unless_get();

// webview_settings rows include the TMDB API key, the paid SportsDB key, and
// any other third-party credential the buyer wires in. Viewers must not see
// raw values. The per-feature admin pages (TMDB Settings, Sports Settings, QR
// Login) are admin-only anyway, so gating the whole endpoint is the right call.
auth_require_admin('Only admins can read settings.');

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $keys = isset($_GET['keys']) ? array_filter(array_map('trim', explode(',', (string)$_GET['keys']))) : null;
    $out  = [];
    if ($keys) {
        $place = implode(',', array_fill(0, count($keys), '?'));
        $rows  = db_all("SELECT key, value FROM webview_settings WHERE key IN ($place)", $keys);
    } else {
        $rows = db_all('SELECT key, value FROM webview_settings ORDER BY key');
    }
    foreach ($rows as $r) $out[$r['key']] = $r['value'];
    json_response(['settings' => $out]);
}

require_method('POST');
list($action, $body) = read_action();

if ($action !== 'save' && $action !== '') json_error('unknown action', 400);

// Accept either {pairs:{k:v,...}} or {settings:[{key,value}, ...]} or flat body
$pairs = [];
if (isset($body['pairs']) && is_array($body['pairs'])) {
    $pairs = $body['pairs'];
} elseif (isset($body['settings']) && is_array($body['settings'])) {
    foreach ($body['settings'] as $row) {
        if (isset($row['key'])) $pairs[(string)$row['key']] = (string)($row['value'] ?? '');
    }
} else {
    // Flat: every body field except 'action' is a setting
    foreach ($body as $k => $v) {
        if ($k === 'action') continue;
        if (is_scalar($v) || $v === null) $pairs[(string)$k] = (string)$v;
    }
}

if (!$pairs) json_error('no key/value pairs', 400);

// Settings keys are all snake_case identifiers — anything else is a typo or
// a probe. Reject the whole batch on the first bad key so the caller gets a
// clear error instead of a silent partial save.
$saved = 0;
$now = time();
foreach ($pairs as $key => $value) {
    if ($key === '' || strlen($key) > 64) continue;
    if (!preg_match('/^[A-Za-z0-9_-]+$/', $key)) {
        json_error('Invalid settings key "' . substr((string)$key, 0, 32) . '".', 400);
    }
    db_exec(
        'INSERT INTO webview_settings (key, value, updated_at) VALUES (?, ?, ?)
         ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at',
        [$key, (string)$value, $now]
    );
    $saved++;
}
json_response(['ok' => true, 'saved' => $saved]);
