<?php
$page_title  = 'VPN';
$page_active = 'vpn';
require __DIR__ . '/includes/page_header.php';
?>

<!-- Header band -->
<div class="-mx-6 -mt-6 px-6 py-5 mb-6 border-b border-dark-700" style="background:#111;">
    <p class="text-xs font-semibold text-primary-400 uppercase tracking-wider mb-1">
        <span class="text-dark-400">Master Panel</span> / IBO ULTRA / VPN
    </p>
    <h2 class="text-2xl font-bold text-white flex items-center gap-3">
        <i class="ph ph-shield-check text-primary-400"></i> VPN
    </h2>
</div>

<div class="card" x-data="{ tab: 'configs' }">
    <!-- Tab nav -->
    <div class="border-b border-dark-700 flex items-center px-4">
        <button @click="tab='configs'" :class="tab==='configs' ? 'tab-active' : ''" class="vpn-tab">
            <i class="ph ph-shield-check"></i> VPN Configs <span class="tab-badge" id="vpn-count-configs">0</span>
        </button>
        <button @click="tab='creds'" :class="tab==='creds' ? 'tab-active' : ''" class="vpn-tab">
            <i class="ph ph-key"></i> Credentials <span class="tab-badge" id="vpn-count-creds">0</span>
        </button>
    </div>

    <!-- ================ VPN Configs tab ================ -->
    <div x-show="tab==='configs'" x-cloak>
        <div class="flex items-center justify-between p-5 border-b border-dark-700">
            <div class="flex items-center gap-2 text-sm text-dark-300">
                <i class="ph ph-shield-check text-primary-400"></i>
                Upload your <code class="mono text-primary-400">.ovpn</code> server files. Credentials are set separately in the Credentials tab.
            </div>
            <div class="flex gap-2">
                <button onclick="document.getElementById('vpn-bulk-zip').click()" class="btn-outline text-xs">
                    <i class="ph ph-download-simple"></i> Bulk ZIP
                </button>
                <input type="file" id="vpn-bulk-zip" accept=".zip" class="hidden">
                <button onclick="openModal('vpn-modal-new')" class="btn-primary text-xs">
                    <i class="ph ph-plus"></i> Add Config
                </button>
            </div>
        </div>
        <div class="overflow-x-auto">
            <table class="compact">
                <thead><tr>
                    <th>Provider</th>
                    <th>Name</th>
                    <th>Country</th>
                    <th>State / City</th>
                    <th>Credentials</th>
                    <th>Config</th>
                    <th class="text-right">Actions</th>
                </tr></thead>
                <tbody id="vpn-config-rows">
                    <tr><td colspan="7" class="text-center text-xs text-dark-500 py-8">Loading…</td></tr>
                </tbody>
            </table>
        </div>
        <div class="px-5 py-3 border-t border-dark-700 text-right">
            <button onclick="deleteAllVpns()" class="text-xs text-red-400 hover:text-red-300">
                <i class="ph ph-trash"></i> Delete all
            </button>
        </div>
    </div>

    <!-- ================ Credentials tab ================ -->
    <div x-show="tab==='creds'" x-cloak>
        <div class="flex items-center justify-between p-5 border-b border-dark-700">
            <div class="flex items-center gap-2 text-sm text-dark-300">
                <i class="ph ph-key text-primary-400"></i>
                A credential is a username/password pair applied to one or more VPN configs.
            </div>
            <button onclick="openAddCred()" class="btn-primary text-xs">
                <i class="ph ph-plus"></i> Add Credential
            </button>
        </div>
        <div class="overflow-x-auto">
            <table class="compact">
                <thead><tr>
                    <th>Provider</th>
                    <th>Username</th>
                    <th>Password</th>
                    <th>Applied to</th>
                    <th class="text-right">Actions</th>
                </tr></thead>
                <tbody id="vpn-cred-rows">
                    <tr><td colspan="5" class="text-center text-xs text-dark-500 py-8">Loading…</td></tr>
                </tbody>
            </table>
        </div>
    </div>
</div>

<!-- =========================================================================
     Add VPN Config modal
     ========================================================================= -->
<div id="vpn-modal-new" class="panel-modal" style="display:none">
    <div class="panel-modal-card lg">
        <div class="panel-modal-head">
            <h3><i class="ph ph-plus-circle text-primary-400 mr-1"></i> Add VPN Config</h3>
            <button onclick="closeModal('vpn-modal-new')" class="icon-btn"><i class="ph ph-x"></i></button>
        </div>
        <form id="vpn-form-new" class="panel-modal-body space-y-3">
            <div class="grid grid-cols-2 gap-3">
                <div><label class="form-label text-xs">Provider</label>
                     <input class="form-input" name="provider" placeholder="PIA / NordVPN / Other" required></div>
                <div><label class="form-label text-xs">Name</label>
                     <input class="form-input" name="name" placeholder="US Atlanta" required></div>
                <div><label class="form-label text-xs">Country</label>
                     <input class="form-input" name="country" placeholder="United States"></div>
                <div><label class="form-label text-xs">State / City</label>
                     <input class="form-input" name="state" placeholder="Atlanta"></div>
                <div class="col-span-2"><label class="form-label text-xs">URL to .ovpn file (optional)</label>
                     <input class="form-input mono" name="url" placeholder="https://example.com/us-atlanta.ovpn"></div>
            </div>
            <div>
                <label class="form-label text-xs">OVPN config (paste full multi-line, or leave blank to fetch from the URL above)</label>
                <textarea class="form-input mono" name="ovpn" rows="10" style="font-size:.75rem"></textarea>
                <p class="text-[11px] text-dark-500 mt-1">Provide either the pasted contents OR a URL — the panel fetches it once and stores the contents.</p>
            </div>
            <div class="grid grid-cols-2 gap-3 items-end">
                <div><label class="form-label text-xs">Sort order</label>
                     <input class="form-input" name="sort_order" type="number" value="0"></div>
                <label class="flex items-center gap-2 text-xs text-dark-200">
                    <input type="checkbox" name="enabled" value="1" checked class="form-check">
                    Enabled
                </label>
            </div>
            <p class="text-[11px] text-dark-500">Username + password live in the Credentials tab so the same pair can be applied to many configs at once.</p>
            <div class="flex justify-end gap-2 pt-2">
                <button type="button" onclick="closeModal('vpn-modal-new')" class="px-4 py-2 text-xs text-dark-400 hover:text-dark-200">Cancel</button>
                <button type="submit" class="btn-primary text-xs"><i class="ph ph-floppy-disk"></i> Create</button>
            </div>
        </form>
    </div>
</div>

<!-- =========================================================================
     Edit VPN Config modal
     ========================================================================= -->
<div id="vpn-modal-edit" class="panel-modal" style="display:none">
    <div class="panel-modal-card lg">
        <div class="panel-modal-head">
            <h3><i class="ph ph-pencil-simple text-primary-400 mr-1"></i> Edit VPN Config</h3>
            <button onclick="closeModal('vpn-modal-edit')" class="icon-btn"><i class="ph ph-x"></i></button>
        </div>
        <form id="vpn-form-edit" class="panel-modal-body space-y-3">
            <input type="hidden" name="id">
            <div class="grid grid-cols-2 gap-3">
                <div><label class="form-label text-xs">Provider</label>
                     <input class="form-input" name="provider" required></div>
                <div><label class="form-label text-xs">Name</label>
                     <input class="form-input" name="name" required></div>
                <div><label class="form-label text-xs">Country</label>
                     <input class="form-input" name="country"></div>
                <div><label class="form-label text-xs">State / City</label>
                     <input class="form-input" name="state"></div>
                <div class="col-span-2"><label class="form-label text-xs">URL to .ovpn file (optional)</label>
                     <input class="form-input mono" name="url" placeholder="https://example.com/us-atlanta.ovpn"></div>
            </div>
            <div>
                <label class="form-label text-xs">OVPN config (blank + URL will re-fetch on save)</label>
                <textarea class="form-input mono" name="ovpn" rows="10" style="font-size:.75rem"></textarea>
            </div>
            <div class="grid grid-cols-2 gap-3 items-end">
                <div><label class="form-label text-xs">Sort order</label>
                     <input class="form-input" name="sort_order" type="number"></div>
                <label class="flex items-center gap-2 text-xs text-dark-200">
                    <input type="checkbox" name="enabled" value="1" class="form-check">
                    Enabled
                </label>
            </div>
            <div class="flex justify-end gap-2 pt-2">
                <button type="button" onclick="closeModal('vpn-modal-edit')" class="px-4 py-2 text-xs text-dark-400 hover:text-dark-200">Cancel</button>
                <button type="submit" class="btn-primary text-xs"><i class="ph ph-floppy-disk"></i> Save</button>
            </div>
        </form>
    </div>
</div>

<!-- =========================================================================
     Add / Edit Credential modal — picks a provider + which configs to apply to
     ========================================================================= -->
<div id="vpn-cred-modal" class="panel-modal" style="display:none">
    <div class="panel-modal-card lg">
        <div class="panel-modal-head">
            <h3><i class="ph ph-key text-primary-400 mr-1"></i> <span id="vpn-cred-modal-title">Add Credential</span></h3>
            <button onclick="closeModal('vpn-cred-modal')" class="icon-btn"><i class="ph ph-x"></i></button>
        </div>
        <form id="vpn-cred-form" class="panel-modal-body space-y-4">
            <!-- Hidden: target ids if editing an existing cred -->
            <input type="hidden" name="prev_username">
            <input type="hidden" name="prev_password">

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="form-label text-xs">Provider</label>
                    <select id="cred-provider" name="provider" class="form-input" required></select>
                </div>
                <div class="row-span-2 lg:col-span-1"></div>
                <div><label class="form-label text-xs">Username</label>
                     <input class="form-input mono" name="username" required></div>
                <div><label class="form-label text-xs">Password</label>
                     <input class="form-input mono" name="password" type="text" required></div>
            </div>

            <div>
                <div class="flex items-center justify-between mb-2">
                    <label class="form-label text-xs mb-0">Apply this credential to</label>
                    <div class="flex gap-2">
                        <button type="button" onclick="credToggle(true)"  class="text-[11px] text-primary-400 hover:text-primary-300">Select all</button>
                        <button type="button" onclick="credToggle(false)" class="text-[11px] text-dark-400 hover:text-dark-200">Clear</button>
                    </div>
                </div>
                <div id="cred-config-list" class="border border-dark-700 rounded-lg p-2 max-h-64 overflow-y-auto bg-dark-900">
                    <p class="text-xs text-dark-500 p-3">Pick a provider above to populate.</p>
                </div>
                <p class="text-[11px] text-dark-500 mt-1">The username and password will be written onto every selected VPN config.</p>
            </div>

            <div class="flex justify-end gap-2 pt-2">
                <button type="button" onclick="closeModal('vpn-cred-modal')" class="px-4 py-2 text-xs text-dark-400 hover:text-dark-200">Cancel</button>
                <button type="submit" class="btn-primary text-xs"><i class="ph ph-floppy-disk"></i> Save</button>
            </div>
        </form>
    </div>
</div>

<style>
.vpn-tab { padding: 14px 18px; display: inline-flex; align-items: center; gap: 8px;
    color: #999; font-size: 13px; border-bottom: 2px solid transparent; cursor: pointer;
    background: transparent; transition: color .15s, border-color .15s; }
.vpn-tab:hover { color: #ccc; }
.tab-active { color: #f39c12 !important; border-bottom-color: #f39c12 !important; }
.tab-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 22px;
    height: 18px; padding: 0 6px; background: #2a2a2a; color: #aaa; border-radius: 10px;
    font-size: 10px; font-weight: 600; }
.tab-active .tab-badge { background: rgba(243,156,18,0.18); color: #f39c12; }
.btn-secondary { background: #2a2a2a; color: #ccc; border: 1px solid #3a3a3a; padding: 6px 12px;
    border-radius: 6px; display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.btn-secondary:hover { background: #3a3a3a; color: white; }
.btn-outline { background: transparent; color: #ccc; border: 1px solid #3a3a3a; padding: 6px 12px;
    border-radius: 6px; display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.btn-outline:hover { background: #1e1e1e; color: white; }
.form-check { accent-color: #f39c12; width: 18px; height: 18px; }
[x-cloak] { display: none !important; }
.provider-pill { display: inline-block; padding: 3px 10px; font-size: 11px; font-weight: 700;
    background: rgba(243,156,18,0.15); color: #f39c12; border-radius: 4px; }
.config-link { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px;
    background: #1e1e1e; border: 1px solid #2a2a2a; border-radius: 4px; font-size: 11px;
    color: #ccc; }
.cred-applied { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px;
    background: rgba(34,197,94,0.10); border: 1px solid rgba(34,197,94,0.35);
    border-radius: 4px; font-size: 11px; color: #4ade80; }
.cred-missing { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px;
    background: rgba(239,68,68,0.10); border: 1px solid rgba(239,68,68,0.35);
    border-radius: 4px; font-size: 11px; color: #f87171; }
.cred-cfg-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px;
    cursor: pointer; }
.cred-cfg-row:hover { background: rgba(255,255,255,.03); }
.cred-cfg-row .name { color: #fff; font-size: 12px; }
.cred-cfg-row .sub  { color: #888; font-size: 11px; margin-left: 6px; }
</style>

<script>
// =============================================================================
// VPN page — single source of truth: vpn_profiles rows fetched once into vpnsCache.
//
//   * "Credentials" is a virtual view: rows grouped by (provider, username, password).
//   * Add / Edit / Delete credential = bulk update username + password on the
//     configs the admin selects.
// =============================================================================
let vpnsCache = [];

// ----------------------------------------------------------------------------
// Load + render
// ----------------------------------------------------------------------------
async function load() {
    try {
        const r = await api.get('api/vpns.php');
        vpnsCache = r.vpns || [];
        document.getElementById('vpn-count-configs').textContent = vpnsCache.length;
        document.getElementById('vpn-count-creds').textContent   = credGroups().length;
        renderConfigs();
        renderCreds();
    } catch (e) { toast(e.message, 'error'); }
}

function renderConfigs() {
    const tbody = document.getElementById('vpn-config-rows');
    if (!vpnsCache.length) {
        tbody.innerHTML = '<tr><td colspan="7" class="text-center text-xs text-dark-500 py-8">No VPN configs.</td></tr>';
        return;
    }
    tbody.innerHTML = vpnsCache.map(v => {
        const credBadge = (v.username && v.password)
            ? `<span class="cred-applied"><i class="ph ph-check"></i> ${escapeHtml(v.username)}</span>`
            : `<span class="cred-missing"><i class="ph ph-warning"></i> Missing</span>`;
        return `
        <tr>
            <td><span class="provider-pill">${escapeHtml(v.provider || '—')}</span></td>
            <td class="text-white">${escapeHtml(v.name || '')}</td>
            <td class="text-white">${escapeHtml(v.country || '')}</td>
            <td class="text-dark-300">${escapeHtml(v.state || '')}</td>
            <td>${credBadge}</td>
            <td>${v.ovpn ? '<span class="config-link"><i class="ph ph-file-text"></i> Inline .ovpn</span>' : '<span class="text-xs text-dark-500">—</span>'}</td>
            <td class="text-right">
                <button class="icon-btn" onclick="openEditVpn(${v.id})" title="Edit"><i class="ph ph-pencil-simple text-primary-400"></i></button>
                <button class="icon-btn danger" onclick="deleteVpn(${v.id})" title="Delete"><i class="ph ph-trash text-red-400"></i></button>
            </td>
        </tr>`;
    }).join('');
}

// Group vpns by (provider, username, password) — non-empty cred only.
function credGroups() {
    const map = new Map();
    for (const v of vpnsCache) {
        if (!v.username && !v.password) continue;
        const key = (v.provider || '—') + '|' + v.username + '|' + v.password;
        if (!map.has(key)) {
            map.set(key, { provider: v.provider || '—', username: v.username || '', password: v.password || '', ids: [], names: [] });
        }
        const g = map.get(key);
        g.ids.push(v.id);
        g.names.push(v.name);
    }
    return Array.from(map.values());
}

function renderCreds() {
    const tbody = document.getElementById('vpn-cred-rows');
    const groups = credGroups();
    if (!groups.length) {
        tbody.innerHTML = '<tr><td colspan="5" class="text-center text-xs text-dark-500 py-8">No credentials yet. Click <strong>Add Credential</strong> to attach a username/password to your configs.</td></tr>';
        return;
    }
    tbody.innerHTML = groups.map(g => {
        const appliedTo = g.names.slice(0, 4).join(', ') + (g.names.length > 4 ? `, +${g.names.length - 4} more` : '');
        return `
        <tr>
            <td><span class="provider-pill">${escapeHtml(g.provider)}</span></td>
            <td class="mono text-white">${escapeHtml(g.username)}</td>
            <td class="mono text-dark-300">••••••••</td>
            <td class="text-dark-300 text-xs">${escapeHtml(appliedTo)} <span class="text-dark-500">(${g.ids.length})</span></td>
            <td class="text-right">
                <button class="icon-btn" title="Edit" onclick='openEditCred(${JSON.stringify(g)})'><i class="ph ph-pencil-simple text-primary-400"></i></button>
                <button class="icon-btn danger" title="Delete" onclick='deleteCred(${JSON.stringify(g)})'><i class="ph ph-trash text-red-400"></i></button>
            </td>
        </tr>`;
    }).join('');
}

// ----------------------------------------------------------------------------
// VPN Config CRUD
// ----------------------------------------------------------------------------
async function deleteVpn(id) {
    if (!(await confirmDanger('Delete this VPN config?'))) return;
    try { await api.post('api/vpns.php', { action: 'delete', id }); toast('Deleted', 'success'); load(); }
    catch (e) { toast(e.message, 'error'); }
}
async function deleteAllVpns() {
    if (!(await confirmDanger('Delete ALL VPN configs? This cannot be undone.'))) return;
    for (const v of vpnsCache) {
        try { await api.post('api/vpns.php', { action: 'delete', id: v.id }); } catch (_) {}
    }
    toast('Cleared', 'success'); load();
}
document.getElementById('vpn-form-new').addEventListener('submit', async (e) => {
    e.preventDefault();
    // Explicit `enabled` — formObject() omits unchecked checkboxes, and the
    // server defaults missing enabled to 1, which silently kept unchecking
    // the box from having any effect. Same pattern the Edit handler uses.
    const body = Object.assign({ action: 'create' }, formObject(e.target));
    body.enabled = e.target.enabled.checked ? 1 : 0;
    try {
        await api.post('api/vpns.php', body);
        toast('Config created', 'success'); closeModal('vpn-modal-new'); e.target.reset(); load();
    } catch (err) { toast(err.message, 'error'); }
});

function openEditVpn(id) {
    const v = vpnsCache.find(x => +x.id === +id);
    if (!v) return;
    const f = document.getElementById('vpn-form-edit');
    f.id.value          = v.id;
    f.provider.value    = v.provider || '';
    f.name.value        = v.name || '';
    f.country.value     = v.country || '';
    f.state.value       = v.state || '';
    f.url.value         = v.url || '';
    f.ovpn.value        = v.ovpn || '';
    f.sort_order.value  = v.sort_order || 0;
    f.enabled.checked   = +v.enabled === 1;
    openModal('vpn-modal-edit');
}
document.getElementById('vpn-form-edit').addEventListener('submit', async (e) => {
    e.preventDefault();
    const body = Object.assign({ action: 'update' }, formObject(e.target));
    body.enabled = e.target.enabled.checked ? 1 : 0;
    try {
        await api.post('api/vpns.php', body);
        toast('Config saved', 'success'); closeModal('vpn-modal-edit'); load();
    } catch (err) { toast(err.message, 'error'); }
});

document.getElementById('vpn-bulk-zip').addEventListener('change', async (e) => {
    const f = e.target.files[0]; if (!f) return;
    const fd = new FormData();
    fd.append('file', f); fd.append('provider', prompt('Provider name for these configs:', 'PIA') || 'Other');
    try {
        const r = await fetch('api/vpns_bulk_zip.php', {
            method: 'POST', credentials: 'same-origin',
            headers: { 'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').content,
                       'X-Requested-With': 'XMLHttpRequest' },
            body: fd,
        });
        const out = await r.json();
        if (out.ok) toast(`Imported ${out.created} config(s)${out.skipped ? `, ${out.skipped} skipped` : ''}`, 'success');
        else toast('Bulk upload failed: ' + (out.error || r.status), 'error');
        e.target.value = ''; load();
    } catch (err) { toast(err.message, 'error'); }
});

// ----------------------------------------------------------------------------
// Credential CRUD (virtual — actually updates rows on vpn_profiles)
// ----------------------------------------------------------------------------
function distinctProviders() {
    return Array.from(new Set(vpnsCache.map(v => v.provider || 'Other'))).sort();
}

function populateCredProviderOptions(selected) {
    const sel = document.getElementById('cred-provider');
    const providers = distinctProviders();
    sel.innerHTML = providers.map(p => `<option value="${escapeHtml(p)}"${p===selected?' selected':''}>${escapeHtml(p)}</option>`).join('');
    if (selected && !providers.includes(selected)) {
        sel.innerHTML = `<option value="${escapeHtml(selected)}" selected>${escapeHtml(selected)}</option>` + sel.innerHTML;
    }
}

function renderCredConfigList(provider, preselectedIds) {
    const host = document.getElementById('cred-config-list');
    const rows = vpnsCache.filter(v => (v.provider || 'Other') === provider);
    if (!rows.length) {
        host.innerHTML = '<p class="text-xs text-dark-500 p-3">No configs in this provider.</p>';
        return;
    }
    const sel = new Set((preselectedIds || []).map(Number));
    host.innerHTML = rows.map(v => `
        <label class="cred-cfg-row" data-id="${v.id}">
            <input type="checkbox" class="form-check cred-cfg-check" value="${v.id}" ${sel.has(+v.id) ? 'checked' : ''}>
            <span class="name">${escapeHtml(v.name || '—')}</span>
            <span class="sub">${escapeHtml(v.country || '')} ${escapeHtml(v.state || '')}</span>
        </label>
    `).join('');
}

function credToggle(checkAll) {
    document.querySelectorAll('#cred-config-list .cred-cfg-check').forEach(cb => cb.checked = !!checkAll);
}

function openAddCred() {
    document.getElementById('vpn-cred-modal-title').textContent = 'Add Credential';
    const f = document.getElementById('vpn-cred-form');
    f.reset();
    f.prev_username.value = '';
    f.prev_password.value = '';
    populateCredProviderOptions(distinctProviders()[0]);
    renderCredConfigList(f.provider.value, []); // none pre-selected
    openModal('vpn-cred-modal');
}

function openEditCred(group) {
    document.getElementById('vpn-cred-modal-title').textContent = 'Edit Credential';
    const f = document.getElementById('vpn-cred-form');
    f.reset();
    f.prev_username.value = group.username;
    f.prev_password.value = group.password;
    f.username.value      = group.username;
    f.password.value      = group.password;
    populateCredProviderOptions(group.provider);
    renderCredConfigList(group.provider, group.ids);
    openModal('vpn-cred-modal');
}

// On provider change, repaint the config list (pre-select rows that already have these creds)
document.getElementById('cred-provider').addEventListener('change', () => {
    const f = document.getElementById('vpn-cred-form');
    const provider = f.provider.value;
    // Pre-tick configs in that provider that already match the current username/password (in edit mode)
    const matching = vpnsCache.filter(v =>
        (v.provider || 'Other') === provider &&
        f.prev_username.value && f.prev_password.value &&
        v.username === f.prev_username.value && v.password === f.prev_password.value
    ).map(v => v.id);
    renderCredConfigList(provider, matching);
});

document.getElementById('vpn-cred-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const f = e.target;
    const provider = f.provider.value;
    const username = f.username.value.trim();
    const password = f.password.value;
    if (!username) { toast('Username required', 'error'); return; }
    const targetIds = [...document.querySelectorAll('#cred-config-list .cred-cfg-check:checked')].map(cb => +cb.value);
    if (!targetIds.length) { toast('Pick at least one config to apply this credential to', 'error'); return; }

    // EDIT MODE: if there's a previous (username,password), and any of those rows are NOT in
    // the new target set, clear their creds first so the group splits cleanly.
    const prev_u = f.prev_username.value;
    const prev_p = f.prev_password.value;
    if (prev_u || prev_p) {
        const wasGroup = vpnsCache.filter(v => v.username === prev_u && v.password === prev_p).map(v => v.id);
        const dropped  = wasGroup.filter(id => !targetIds.includes(id));
        for (const id of dropped) {
            try { await api.post('api/vpns.php', { action: 'update', id, username: '', password: '' }); } catch (_) {}
        }
    }

    let ok = 0, fail = 0;
    for (const id of targetIds) {
        try {
            await api.post('api/vpns.php', { action: 'update', id, username, password, provider });
            ok++;
        } catch (_) { fail++; }
    }
    toast(`Saved on ${ok} config${ok===1?'':'s'}${fail?` (${fail} failed)`:''}`, fail ? 'warn' : 'success');
    closeModal('vpn-cred-modal');
    load();
});

async function deleteCred(group) {
    if (!(await confirmDanger(`Remove these credentials from ${group.ids.length} VPN config${group.ids.length === 1 ? '' : 's'}? The server files will stay.`))) return;
    let ok = 0;
    for (const id of group.ids) {
        try { await api.post('api/vpns.php', { action: 'update', id, username: '', password: '' }); ok++; } catch (_) {}
    }
    toast(`Removed credential from ${ok} config${ok===1?'':'s'}`, 'success');
    load();
}

load();
</script>

<?php require __DIR__ . '/includes/page_footer.php'; ?>
