<?php
/**
 * Borrador persistente del asistente de instalación (sin contraseñas).
 */

declare(strict_types=1);

require_once dirname(__DIR__) . '/core/auth/session.php';
require_once dirname(__DIR__) . '/core/security/csrf.php';

const ANTARA_INSTALL_WIZARD_DRAFT_VERSION = 1;

/** Segundos que el asistente mantiene la sesión aunque cambie IP o agente de usuario. */
const ANTARA_INSTALL_WIZARD_SESSION_GRACE_SEC = 604800;

/**
 * Mantiene viva la sesión del instalador y garantiza token CSRF.
 */
function antara_install_wizard_keepalive(): void
{
    if (PHP_SAPI !== 'cli') {
        @ini_set('session.gc_maxlifetime', (string) ANTARA_INSTALL_WIZARD_SESSION_GRACE_SEC);
    }
    AntaraSession::start();
    $_SESSION['install_wizard_active'] = time();
    AntaraCsrf::token();
}

/**
 * @return array{valid: bool, csrf: string, relaxed: bool}
 */
function antara_install_wizard_verify_csrf(?string $token, string $action, ?array $settings = null): array
{
    antara_install_wizard_keepalive();
    $current = AntaraCsrf::token();
    if (AntaraCsrf::isValid($token)) {
        return ['valid' => true, 'csrf' => $current, 'relaxed' => false];
    }
    $inProgress = antara_install_wizard_has_progress($settings);
    $isAutosave = $action === 'wizard_autosave';
    $isXhr = isset($_SERVER['HTTP_X_REQUESTED_WITH'])
        && strtolower((string) $_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    if ($inProgress && $isAutosave && $isXhr) {
        return ['valid' => true, 'csrf' => $current, 'relaxed' => true];
    }

    return ['valid' => false, 'csrf' => $current, 'relaxed' => false];
}

/**
 * @return string Ruta absoluta a install_wizard_draft.json
 */
function antara_install_wizard_draft_path(): string
{
    if (!defined('ANTARA_ROOT')) {
        define('ANTARA_ROOT', defined('GRID_ROOT') ? GRID_ROOT : dirname(__DIR__));
    }
    require_once ANTARA_ROOT . '/core/security/paths.php';

    return AntaraPaths::config() . DIRECTORY_SEPARATOR . 'install_wizard_draft.json';
}

/**
 * @return array<string, mixed>
 */
function antara_install_wizard_read_draft(): array
{
    $path = antara_install_wizard_draft_path();
    if (!is_file($path)) {
        return [];
    }
    $raw = @file_get_contents($path);
    if ($raw === false || $raw === '') {
        return [];
    }
    $data = json_decode($raw, true);
    if (!is_array($data)) {
        return [];
    }

    return $data;
}

function antara_install_wizard_clear_draft(): void
{
    $path = antara_install_wizard_draft_path();
    if (is_file($path)) {
        @unlink($path);
    }
}

/**
 * @param array<string, mixed> $patch
 */
function antara_install_wizard_merge_draft(array $patch): bool
{
    $path = antara_install_wizard_draft_path();
    $dir = dirname($path);
    if (!is_dir($dir) && !@mkdir($dir, 0755, true)) {
        return false;
    }
    if (!is_dir($dir) || !is_writable($dir)) {
        return false;
    }

    $cur = antara_install_wizard_read_draft();
    unset($patch['password'], $patch['password_confirm']);
    $merged = array_merge($cur, $patch);
    $merged['version'] = ANTARA_INSTALL_WIZARD_DRAFT_VERSION;
    $merged['updated_at'] = gmdate('c');
    if (isset($merged['max_step'])) {
        $merged['max_step'] = max(1, min(3, (int) $merged['max_step']));
    }

    require_once ANTARA_ROOT . '/includes/settings_helpers.php';
    $json = json_encode($merged, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    if ($json === false) {
        return false;
    }

    return grid_atomic_write_file($path, $json . "\n");
}

/**
 * @param array<string, mixed>|null $settings
 */
function antara_install_wizard_settings_indicate_step1(?array $settings): bool
{
    if (!is_array($settings)) {
        return false;
    }
    $kind = (string) ($settings['deploymentKind'] ?? '');
    if ($kind === 'personal') {
        return trim((string) ($settings['personalDisplayName'] ?? '')) !== '';
    }
    if ($kind === 'company') {
        return trim((string) ($settings['companyName'] ?? '')) !== '';
    }

    return false;
}

/**
 * Hay borrador o settings del paso 1 ya guardados.
 *
 * @param array<string, mixed>|null $settings
 */
function antara_install_wizard_has_progress(?array $settings = null): bool
{
    $draft = antara_install_wizard_read_draft();
    if ($draft !== []) {
        return true;
    }
    if ($settings === null) {
        return false;
    }

    return antara_install_wizard_settings_indicate_step1($settings);
}

function antara_install_wizard_max_step(): int
{
    $draft = antara_install_wizard_read_draft();
    $ms = (int) ($draft['max_step'] ?? 1);

    return max(1, min(3, $ms > 0 ? $ms : 1));
}

function antara_install_wizard_clear_install_session(): void
{
    unset(
        $_SESSION['install_wizard_company_ok'],
        $_SESSION['install_pending_finish'],
        $_SESSION['install_pending_branch_users'],
        $_SESSION['install_profile_image_saved'],
        $_SESSION['install_flash_notices'],
        $_SESSION['install_wizard_resume_notice']
    );
}

/**
 * Restaura flags de sesión desde borrador + settings (sin contraseña).
 *
 * @param array<string, mixed> $settings
 */
function antara_install_wizard_sync_session_from_draft(array $settings): void
{
    if (!antara_install_wizard_settings_indicate_step1($settings)) {
        return;
    }
    $_SESSION['install_wizard_company_ok'] = 1;

    $draft = antara_install_wizard_read_draft();
    $maxStep = antara_install_wizard_max_step();
    if ($maxStep < 2) {
        return;
    }

    $mode = (string) ($draft['access_mode'] ?? '');
    if ($mode !== 'public' && $mode !== 'first_user') {
        return;
    }

    $pend = ['access_mode' => $mode];
    if ($mode === 'first_user') {
        $pend['email'] = (string) ($draft['email'] ?? '');
        $pend['username'] = (string) ($draft['username'] ?? '');
        $pend['phone'] = (string) ($draft['phone'] ?? '');
        $pend['branchId'] = (string) ($settings['defaultBranchId'] ?? '');
    }

    if ($mode === 'public' && $maxStep >= 2) {
        $_SESSION['install_pending_finish'] = $pend;

        return;
    }

    if ($maxStep >= 3) {
        $existing = $_SESSION['install_pending_finish'] ?? null;
        if (is_array($existing)) {
            $existingMode = (string) ($existing['access_mode'] ?? '');
            if ($existingMode === 'public') {
                return;
            }
            if ($existingMode === 'first_user' && (string) ($existing['password'] ?? '') !== '') {
                return;
            }
        }
        $_SESSION['install_pending_finish'] = $pend;
    }
}

/**
 * Restaura flags de sesión del paso 2 desde POST de autosave (contraseña solo en sesión).
 *
 * @param array<string, mixed> $body
 * @param array<string, mixed> $settings
 */
function antara_install_wizard_apply_session_from_step2_body(array $body, array $settings): void
{
    if (!antara_install_wizard_settings_indicate_step1($settings)) {
        return;
    }
    $_SESSION['install_wizard_company_ok'] = 1;

    $mode = (string) ($body['access_mode'] ?? '');
    if ($mode === 'public') {
        $_SESSION['install_pending_finish'] = ['access_mode' => 'public'];

        return;
    }
    if ($mode !== 'first_user') {
        return;
    }

    $password = (string) ($body['password'] ?? '');
    $pend = [
        'access_mode' => 'first_user',
        'email' => trim((string) ($body['email'] ?? '')),
        'username' => trim((string) ($body['username'] ?? '')),
        'phone' => trim((string) ($body['phone'] ?? '')),
        'branchId' => (string) ($settings['defaultBranchId'] ?? ''),
    ];
    if ($password !== '') {
        $pend['password'] = $password;
    } elseif (is_array($_SESSION['install_pending_finish'] ?? null)) {
        $prevPwd = (string) ($_SESSION['install_pending_finish']['password'] ?? '');
        if ($prevPwd !== '') {
            $pend['password'] = $prevPwd;
        }
    }
    $_SESSION['install_pending_finish'] = $pend;
}

/**
 * @param array<string, mixed> $body
 */
function antara_install_wizard_patch_step1_from_body(array $body): array
{
    return [
        'deployment_kind' => (string) ($body['deployment_kind'] ?? 'personal'),
        'personalDisplayName' => trim((string) ($body['personalDisplayName'] ?? '')),
        'personal_location_json' => (string) ($body['personal_location_json'] ?? ''),
        'personalAddress' => trim((string) ($body['personalAddress'] ?? '')),
        'companyName' => trim((string) ($body['companyName'] ?? '')),
        'companyAddress' => trim((string) ($body['companyAddress'] ?? '')),
        'company_location_json' => (string) ($body['company_location_json'] ?? ''),
        'companyEmail' => trim((string) ($body['companyEmail'] ?? '')),
        'companyPhone' => trim((string) ($body['companyPhone'] ?? '')),
        'branch_access_policy' => (string) ($body['branch_access_policy'] ?? 'explicit_grant'),
        'branch_name' => is_array($body['branch_name'] ?? null) ? $body['branch_name'] : [],
        'branch_id' => is_array($body['branch_id'] ?? null) ? $body['branch_id'] : [],
        'branch_address' => is_array($body['branch_address'] ?? null) ? $body['branch_address'] : [],
        'branch_location_json' => is_array($body['branch_location_json'] ?? null) ? $body['branch_location_json'] : [],
        'branch_email' => is_array($body['branch_email'] ?? null) ? $body['branch_email'] : [],
        'branch_phone' => is_array($body['branch_phone'] ?? null) ? $body['branch_phone'] : [],
        'branch_use_primary_logo' => is_array($body['branch_use_primary_logo'] ?? null) ? $body['branch_use_primary_logo'] : [],
        'branch_user_create' => is_array($body['branch_user_create'] ?? null) ? $body['branch_user_create'] : [],
        'branch_user_username' => is_array($body['branch_user_username'] ?? null) ? $body['branch_user_username'] : [],
        'branch_user_email' => is_array($body['branch_user_email'] ?? null) ? $body['branch_user_email'] : [],
        'branch_user_phone' => is_array($body['branch_user_phone'] ?? null) ? $body['branch_user_phone'] : [],
        'branch_user_role' => is_array($body['branch_user_role'] ?? null) ? $body['branch_user_role'] : [],
        'access_mode' => (string) ($body['access_mode'] ?? ''),
        'email' => trim((string) ($body['email'] ?? '')),
        'username' => trim((string) ($body['username'] ?? '')),
        'phone' => trim((string) ($body['phone'] ?? '')),
        'matrix_branch_id' => trim((string) ($body['matrix_branch_id'] ?? '')),
        'open_profile_pane' => !empty($body['open_profile_pane']),
    ];
}

/**
 * Autoguardado parcial del asistente (borrador + sesión cuando aplica).
 *
 * @param array<string, mixed> $body
 */
function antara_install_wizard_save_autosave_from_body(array $body, int $wizardStep, array $settings): bool
{
    $wizardStep = max(1, min(3, $wizardStep));
    $curMax = antara_install_wizard_max_step();

    if ($wizardStep === 1) {
        $patch = antara_install_wizard_patch_step1_from_body($body);
        $patch['max_step'] = max(1, $curMax);

        return antara_install_wizard_merge_draft($patch);
    }

    if ($wizardStep === 2) {
        $advance = !empty($body['wizard_advance_step']);
        antara_install_wizard_save_step2_from_body($body, $advance);
        antara_install_wizard_apply_session_from_step2_body($body, $settings);

        return true;
    }

    antara_install_wizard_save_step3_from_body($body);
    $patch = ['max_step' => max($curMax, 3)];
    if (array_key_exists('open_profile_pane', $body)) {
        $patch['open_profile_pane'] = !empty($body['open_profile_pane']);
    }

    return antara_install_wizard_merge_draft($patch);
}

/**
 * @param array<string, mixed> $settings
 */
function antara_install_wizard_save_step1_from_settings(array $settings, bool $openProfilePane = false): void
{
    require_once dirname(__DIR__) . '/includes/install_geo.php';

    $patch = [
        'max_step' => max(antara_install_wizard_max_step(), 2),
        'deployment_kind' => (string) ($settings['deploymentKind'] ?? 'personal'),
        'personalDisplayName' => (string) ($settings['personalDisplayName'] ?? ''),
        'companyName' => (string) ($settings['companyName'] ?? ''),
        'companyAddress' => (string) ($settings['companyAddress'] ?? ''),
        'company_location_json' => json_encode(
            antara_install_company_location_from_settings($settings),
            JSON_UNESCAPED_UNICODE
        ) ?: '',
        'personal_location_json' => json_encode(
            antara_install_company_location_from_settings($settings),
            JSON_UNESCAPED_UNICODE
        ) ?: '',
        'companyEmail' => (string) ($settings['companyEmail'] ?? ''),
        'companyPhone' => (string) ($settings['companyPhone'] ?? ''),
        'branch_access_policy' => (string) (($settings['branchAccessDefaults'] ?? [])['crossBranchAccessPolicy'] ?? 'explicit_grant'),
        'open_profile_pane' => $openProfilePane,
    ];
    $branchNames = [];
    $branchCodes = [];
    $branchIds = [];
    $branchAddresses = [];
    $branchEmails = [];
    $branchPhones = [];
    $branchLocJson = [];
    $allBranches = is_array($settings['branches'] ?? null) ? $settings['branches'] : [];
    $draftBranches = count($allBranches) > 1 ? array_values(array_slice($allBranches, 1)) : [];
    foreach ($draftBranches as $br) {
        if (!is_array($br)) {
            continue;
        }
        $branchNames[] = (string) ($br['name'] ?? '');
        $branchCodes[] = (string) ($br['code'] ?? '');
        $branchIds[] = (string) ($br['id'] ?? '');
        $branchAddresses[] = (string) ($br['address'] ?? '');
        $branchEmails[] = (string) ($br['email'] ?? '');
        $branchPhones[] = (string) ($br['phone'] ?? '');
        $loc = antara_install_branch_location_from_row($br);
        $branchLocJson[] = json_encode($loc, JSON_UNESCAPED_UNICODE) ?: '';
    }
    $patch['branch_name'] = $branchNames;
    $patch['branch_code'] = $branchCodes;
    $patch['branch_id'] = $branchIds;
    $patch['branch_address'] = $branchAddresses;
    $patch['branch_email'] = $branchEmails;
    $patch['branch_phone'] = $branchPhones;
    $patch['branch_location_json'] = $branchLocJson;
    $patch['matrix_branch_id'] = (string) ($settings['defaultBranchId'] ?? '');
    if ($patch['matrix_branch_id'] === '' && isset($allBranches[0]['id'])) {
        $patch['matrix_branch_id'] = (string) $allBranches[0]['id'];
    }
    antara_install_wizard_merge_draft($patch);
}

/**
 * @param array<string, mixed> $body POST body
 */
function antara_install_wizard_save_step2_from_body(array $body, bool $advanceToStep3 = false): void
{
    $patch = [
        'max_step' => $advanceToStep3 ? max(antara_install_wizard_max_step(), 3) : max(antara_install_wizard_max_step(), 2),
        'access_mode' => (string) ($body['access_mode'] ?? ''),
        'email' => trim((string) ($body['email'] ?? '')),
        'username' => trim((string) ($body['username'] ?? '')),
        'phone' => trim((string) ($body['phone'] ?? '')),
    ];
    antara_install_wizard_merge_draft($patch);
}

/**
 * @param array<string, mixed> $body POST body
 */
function antara_install_wizard_save_step3_from_body(array $body): void
{
    $keys = [
        'pwa_name', 'pwa_short_name', 'pwa_description', 'pwa_lang', 'pwa_theme_color',
        'pwa_background_color', 'pwa_display', 'pwa_orientation', 'pwa_start_url', 'pwa_scope',
        'pwa_icon192_rel', 'pwa_icon512_rel', 'pwa_maskable_rel', 'pwa_apple_rel', 'pwa_splash_rel',
        'pwa_crop_json', 'pwa_icon_mode',
    ];
    $patch = ['max_step' => max(antara_install_wizard_max_step(), 3)];
    foreach ($keys as $k) {
        if (array_key_exists($k, $body)) {
            $patch[$k] = is_string($body[$k]) ? $body[$k] : (string) $body[$k];
        }
    }
    if (array_key_exists('pwa_enabled', $body)) {
        $patch['pwa_enabled'] = !empty($body['pwa_enabled']) ? '1' : '0';
    }
    antara_install_wizard_merge_draft($patch);
}

/**
 * Valor de campo con prioridad POST → borrador → settings → default.
 *
 * @param array<string, mixed> $draft
 * @param array<string, mixed> $settings
 * @param mixed $default
 * @return mixed
 */
function antara_install_wizard_field(
    string $key,
    $postValue,
    array $draft,
    array $settings,
    $default = ''
) {
    if ($postValue !== null && $postValue !== '') {
        return $postValue;
    }
    if (array_key_exists($key, $draft) && $draft[$key] !== '' && $draft[$key] !== null) {
        return $draft[$key];
    }
    $settingsMap = [
        'deployment_kind' => 'deploymentKind',
        'personalDisplayName' => 'personalDisplayName',
        'companyName' => 'companyName',
        'companyAddress' => 'companyAddress',
        'company_location_json' => 'company_location_json',
        'companyEmail' => 'companyEmail',
        'companyPhone' => 'companyPhone',
    ];
    if (isset($settingsMap[$key]) && isset($settings[$settingsMap[$key]])) {
        $v = $settings[$settingsMap[$key]];
        if ($v !== '' && $v !== null) {
            return $v;
        }
    }
    if ($key === 'company_location_json' || $key === 'personal_location_json') {
        require_once dirname(__DIR__) . '/includes/install_geo.php';
        $loc = antara_install_company_location_from_settings($settings);
        $enc = json_encode($loc, JSON_UNESCAPED_UNICODE);

        return $enc !== false && $enc !== '' && !antara_install_location_is_empty($loc) ? $enc : $default;
    }
    if ($key === 'personalAddress') {
        $addr = trim((string) ($settings['companyAddress'] ?? ''));

        return $addr !== '' ? $addr : $default;
    }
    if ($key === 'branch_access_policy') {
        $pol = (string) (($settings['branchAccessDefaults'] ?? [])['crossBranchAccessPolicy'] ?? '');

        return $pol !== '' ? $pol : $default;
    }

    return $default;
}

/**
 * @param array<string, mixed> $draft
 * @param array<string, mixed> $settings
 * @return list<array<string, mixed>>
 */
function antara_install_wizard_branch_rows(array $draft, array $settings, ?array $post = null): array
{
    require_once dirname(__DIR__) . '/includes/install_geo.php';

    $fromArrays = static function (
        array $names,
        array $ids,
        array $addrs,
        array $emails,
        array $phones,
        array $useLogo,
        array $logoRels,
        array $locJsons = [],
        array $userCreates = [],
        array $userNames = [],
        array $userEmails = [],
        array $userPhones = [],
        array $userRoles = []
    ): array {
        $rows = [];
        foreach ($names as $i => $nameRaw) {
            $name = trim((string) $nameRaw);
            if ($name === '') {
                continue;
            }
            $locJson = isset($locJsons[$i]) ? (string) $locJsons[$i] : '';
            $merged = antara_install_merge_location_into_address(antara_install_parse_location_json($locJson));
            $address = isset($addrs[$i]) ? trim((string) $addrs[$i]) : '';
            if ($address === '') {
                $address = $merged['address'];
            }
            $createUser = !empty($userCreates[$i]) && (string) $userCreates[$i] !== '0';
            $rows[] = [
                'id' => isset($ids[$i]) ? (string) $ids[$i] : '',
                'name' => $name,
                'code' => '',
                'address' => $address,
                'location' => $merged['location'],
                'email' => isset($emails[$i]) ? (string) $emails[$i] : '',
                'phone' => isset($phones[$i]) ? (string) $phones[$i] : '',
                'useCompanyContact' => false,
                'usePrimaryLogo' => !empty($useLogo[$i]),
                'logoRel' => isset($logoRels[$i]) ? (string) $logoRels[$i] : '',
                'createUser' => $createUser,
                'userUsername' => isset($userNames[$i]) ? (string) $userNames[$i] : '',
                'userEmail' => isset($userEmails[$i]) ? (string) $userEmails[$i] : '',
                'userPhone' => isset($userPhones[$i]) ? (string) $userPhones[$i] : '',
                'userRole' => isset($userRoles[$i]) ? (string) $userRoles[$i] : 'admin',
            ];
        }

        return $rows;
    };

    if ($post !== null && isset($post['branch_name']) && is_array($post['branch_name'])) {
        $rows = $fromArrays(
            $post['branch_name'],
            is_array($post['branch_id'] ?? null) ? $post['branch_id'] : [],
            is_array($post['branch_address'] ?? null) ? $post['branch_address'] : [],
            is_array($post['branch_email'] ?? null) ? $post['branch_email'] : [],
            is_array($post['branch_phone'] ?? null) ? $post['branch_phone'] : [],
            is_array($post['branch_use_primary_logo'] ?? null) ? $post['branch_use_primary_logo'] : [],
            [],
            is_array($post['branch_location_json'] ?? null) ? $post['branch_location_json'] : [],
            is_array($post['branch_user_create'] ?? null) ? $post['branch_user_create'] : [],
            is_array($post['branch_user_username'] ?? null) ? $post['branch_user_username'] : [],
            is_array($post['branch_user_email'] ?? null) ? $post['branch_user_email'] : [],
            is_array($post['branch_user_phone'] ?? null) ? $post['branch_user_phone'] : [],
            is_array($post['branch_user_role'] ?? null) ? $post['branch_user_role'] : []
        );
        if ($rows !== []) {
            return $rows;
        }
    }
    if (isset($draft['branch_name']) && is_array($draft['branch_name']) && $draft['branch_name'] !== []) {
        $rows = $fromArrays(
            $draft['branch_name'],
            is_array($draft['branch_id'] ?? null) ? $draft['branch_id'] : [],
            is_array($draft['branch_address'] ?? null) ? $draft['branch_address'] : [],
            is_array($draft['branch_email'] ?? null) ? $draft['branch_email'] : [],
            is_array($draft['branch_phone'] ?? null) ? $draft['branch_phone'] : [],
            is_array($draft['branch_use_primary_logo'] ?? null) ? $draft['branch_use_primary_logo'] : [],
            is_array($draft['branch_logo_rel'] ?? null) ? $draft['branch_logo_rel'] : [],
            is_array($draft['branch_location_json'] ?? null) ? $draft['branch_location_json'] : [],
            is_array($draft['branch_user_create'] ?? null) ? $draft['branch_user_create'] : [],
            is_array($draft['branch_user_username'] ?? null) ? $draft['branch_user_username'] : [],
            is_array($draft['branch_user_email'] ?? null) ? $draft['branch_user_email'] : [],
            is_array($draft['branch_user_phone'] ?? null) ? $draft['branch_user_phone'] : [],
            is_array($draft['branch_user_role'] ?? null) ? $draft['branch_user_role'] : []
        );
        if ($rows !== []) {
            return $rows;
        }
    }
    $rows = [];
    $settingsBranches = is_array($settings['branches'] ?? null) ? $settings['branches'] : [];
    if (count($settingsBranches) > 1) {
        $settingsBranches = array_values(array_slice($settingsBranches, 1));
    } else {
        $settingsBranches = [];
    }
    foreach ($settingsBranches as $br) {
        if (!is_array($br)) {
            continue;
        }
        $n = trim((string) ($br['name'] ?? ''));
        if ($n === '') {
            continue;
        }
        $rows[] = [
            'id' => (string) ($br['id'] ?? ''),
            'name' => $n,
            'code' => (string) ($br['code'] ?? ''),
            'address' => (string) ($br['address'] ?? ''),
            'location' => antara_install_branch_location_from_row($br),
            'email' => (string) ($br['email'] ?? ''),
            'phone' => (string) ($br['phone'] ?? ''),
            'useCompanyContact' => false,
            'usePrimaryLogo' => !empty($br['usePrimaryLogo']),
            'logoRel' => (string) ($br['logoRel'] ?? ''),
        ];
    }
    return $rows;
}

/**
 * Lee campo PWA: POST → borrador → settings pwa → fallback.
 *
 * @param array<string, mixed> $draft
 * @param array<string, mixed> $pwaSettings
 */
function antara_install_wizard_pwa_field(
    string $field,
    bool $isPwaPost,
    array $draft,
    array $pwaSettings,
    string $fallback
): string {
    if ($isPwaPost && isset($_POST[$field]) && is_string($_POST[$field])) {
        return $_POST[$field];
    }
    if (isset($draft[$field]) && is_string($draft[$field]) && $draft[$field] !== '') {
        return $draft[$field];
    }
    $pwaKeyMap = [
        'pwa_name' => 'name',
        'pwa_short_name' => 'shortName',
        'pwa_description' => 'description',
        'pwa_lang' => 'lang',
        'pwa_theme_color' => 'themeColor',
        'pwa_background_color' => 'backgroundColor',
        'pwa_display' => 'display',
        'pwa_orientation' => 'orientation',
        'pwa_start_url' => 'startUrl',
        'pwa_scope' => 'scope',
        'pwa_icon192_rel' => 'icon192Rel',
        'pwa_icon512_rel' => 'icon512Rel',
        'pwa_maskable_rel' => 'iconMaskable512Rel',
        'pwa_apple_rel' => 'appleTouch180Rel',
        'pwa_splash_rel' => 'splashLaunchRel',
    ];
    if (isset($pwaKeyMap[$field])) {
        $sk = $pwaKeyMap[$field];
        $v = (string) ($pwaSettings[$sk] ?? '');
        if ($v !== '') {
            return $v;
        }
    }

    return $fallback;
}
