// ── Advanced Security · Field Encryption ─────────────────────────────────
// Compact per-table accordion (mirrors Row-Level Security). Each table expands
// to its columns with a per-column encrypt toggle. Columns lazy-load on expand.
// NOTE: this is the CONSOLE config only — generated-app enforcement is separate.

let encTables = [];
let encColumns = {};          // table -> [cols] | null (unavailable) | undefined (unloaded)
let encColLoading = new Set();
let encExpanded = new Set();
let encEnabled = new Set();    // "table|column" currently switched on
let encInitial = new Set();    // enabled on load (so turning one OFF persists a 0)
let encIsOwner = false;

const feEsc = (s) => (window.escapeHtml ? window.escapeHtml(String(s ?? '')) :
    String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])));
const feKey = (t, c) => `${t}|${c}`;
const feCssEsc = (s) => (window.CSS && CSS.escape) ? CSS.escape(s) : String(s).replace(/["\\]/g, '\\$&');

const FE_TIP = {
    toggle: 'When ON, the app encrypts this column before saving (AES-256) and decrypts it on read. Best for truly sensitive values — SSNs, card numbers, API secrets.',
    search: 'Encrypted columns can only be matched exactly (each value encrypts uniquely), so avoid encrypting columns you search, sort or filter on.'
};

// Columns whose name hints they hold sensitive data → a subtle suggestion chip.
function feHint(col) {
    const c = col.toLowerCase();
    if (/(ssn|social_security|tax_id|national_id)/.test(c)) return 'SSN / tax ID';
    if (/(card|credit|cvv|iban|account_number|routing)/.test(c)) return 'financial';
    if (/(secret|api_key|apikey|token|private_key|password|passwd)/.test(c)) return 'secret';
    if (/(dob|birth|passport|licen[sc]e)/.test(c)) return 'personal';
    if (/(phone|mobile|address)/.test(c)) return 'contact';
    return '';
}

async function renderEncryption() {
    if (!window.securitySettings?.db_auth_enabled) {
        const c = document.getElementById('securityPageContainer');
        if (c) c.innerHTML = '<div class="alert alert-warning m-2">Database authentication is not enabled. Please enable it in the Settings tab first.</div>';
        return;
    }
    const container = document.getElementById('securityPageContainer');
    if (!container) return;
    container.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary"></div></div>';

    try {
        const [tablesRes, settingsRes] = await Promise.all([
            fetch(`${baseUrl}/project/${projectSlug}/security/tables`),
            fetch(`${baseUrl}/project/${projectSlug}/security/field-encryption`)
        ]);
        const tablesData = await tablesRes.json();
        const settingsData = await settingsRes.json();
        if (!tablesData.success) throw new Error(tablesData.message || 'Could not load tables');
        if (!settingsData.success) throw new Error(settingsData.message || 'Could not load settings');

        // Encrypt columns on your own business tables — hide platform/system tables
        // via the shared classifier (window.PP_SYSTEM, one source of truth).
        const allTables = tablesData.allTables || tablesData.tables || [];
        encTables = window.PP_SYSTEM ? allTables.filter(t => !window.PP_SYSTEM.isSystem(t)) : allTables;
        encIsOwner = !!tablesData.isOwner;

        encEnabled = new Set();
        (settingsData.settings || []).forEach(s => { if (Number(s.enabled)) encEnabled.add(feKey(s.table_name, s.column_name)); });
        encInitial = new Set(encEnabled);

        renderEncShell(container);
    } catch (e) {
        console.error('renderEncryption error:', e);
        container.innerHTML = `<div class="alert alert-danger m-2">Failed to load data: ${feEsc(e.message)}</div>`;
    }
}

function encCount(table) {
    let n = 0;
    encEnabled.forEach(k => { if (k.slice(0, table.length + 1) === table + '|') n++; });
    return n;
}

function renderEncShell(container) {
    injectEncStyles();
    container.innerHTML = `
    <div class="fe">
        <div class="fe-bar">
            <span class="fe-lead"><i class="bi bi-shield-lock"></i> Encrypt sensitive columns at rest — the value is stored as ciphertext and decrypted only when read.</span>
            <div class="fe-bar-actions">
                <div class="fe-search"><i class="bi bi-search"></i><input type="text" id="encSearch" placeholder="Filter tables…" autocomplete="off"></div>
                <button class="fe-btn ghost" id="encTipsBtn"><i class="bi bi-question-circle"></i> Tips</button>
            </div>
        </div>

        <div class="fe-acc" id="encAcc"></div>

        <div class="fe-foot">
            <span class="fe-status" id="encStatus"></span>
            <div class="fe-foot-actions">
                <button class="fe-btn ghost" id="encMigrateBtn" data-bs-toggle="tooltip" title="Encrypt the plaintext values already stored in the columns you've switched on. Runs once; skips anything already encrypted."><i class="bi bi-shield-lock"></i> Encrypt existing rows</button>
                <button class="fe-btn primary" id="saveEncryptionSettings"><i class="bi bi-save"></i> Save settings</button>
            </div>
        </div>
    </div>
    ${encTipsModalHtml()}
    `;

    renderEncAccordion('');
    refreshEncStatus();
    initEncTooltips(container);

    document.getElementById('encSearch')?.addEventListener('input', e => renderEncAccordion(e.target.value.trim().toLowerCase()));
    document.getElementById('saveEncryptionSettings')?.addEventListener('click', saveEncryption);
    document.getElementById('encMigrateBtn')?.addEventListener('click', migrateEncryption);
    document.getElementById('encTipsBtn')?.addEventListener('click', () => {
        try { new bootstrap.Modal(document.getElementById('encTipsModal')).show(); } catch (e) {}
    });
}

function renderEncAccordion(filter) {
    const acc = document.getElementById('encAcc');
    if (!acc) return;
    const tables = filter ? encTables.filter(t => t.toLowerCase().includes(filter)) : encTables;

    if (!encTables.length) {
        acc.innerHTML = '<div class="fe-empty"><i class="bi bi-table"></i><p>No business tables to encrypt yet. Create a table first.</p></div>';
        return;
    }
    if (!tables.length) {
        acc.innerHTML = '<div class="fe-empty"><i class="bi bi-search"></i><p>No tables match your filter.</p></div>';
        return;
    }

    acc.innerHTML = tables.map(table => {
        const count = encCount(table);
        const open = encExpanded.has(table);
        const badge = count ? `<span class="fe-tbadge active"><i class="bi bi-lock-fill"></i> ${count} encrypted</span>` : `<span class="fe-tbadge">None</span>`;
        return `
        <div class="fe-item ${open ? 'open' : ''}" data-table="${feEsc(table)}">
            <button type="button" class="fe-item-head" data-table="${feEsc(table)}">
                <i class="bi bi-chevron-right fe-caret"></i>
                <i class="bi bi-table fe-item-ic"></i>
                <span class="fe-item-name">${feEsc(table)}</span>
                ${badge}
            </button>
            <div class="fe-item-body">${open ? renderEncColumns(table) : ''}</div>
        </div>`;
    }).join('');

    acc.querySelectorAll('.fe-item-head').forEach(h => h.addEventListener('click', () => toggleEncTable(h.dataset.table)));
    tables.forEach(t => { if (encExpanded.has(t)) bindEncColumnEvents(t); });
    initEncTooltips(acc);
}

async function toggleEncTable(table) {
    const item = document.querySelector(`.fe-item[data-table="${feCssEsc(table)}"]`);
    if (!item) return;
    const body = item.querySelector('.fe-item-body');
    if (encExpanded.has(table)) {
        encExpanded.delete(table); item.classList.remove('open'); body.innerHTML = '';
        return;
    }
    encExpanded.add(table); item.classList.add('open');
    body.innerHTML = '<div class="fe-loading"><div class="spinner-border spinner-border-sm text-primary"></div> Loading columns…</div>';
    await loadEncColumns(table);
    body.innerHTML = renderEncColumns(table);
    bindEncColumnEvents(table);
    initEncTooltips(body);
}

async function loadEncColumns(table) {
    if (encColumns[table] !== undefined) return encColumns[table];
    if (encColLoading.has(table)) return;
    encColLoading.add(table);
    try {
        const res = await fetch(`${baseUrl}/project/${projectSlug}/security/columns`, {
            method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ table })
        });
        const data = await res.json();
        encColumns[table] = (data.success && Array.isArray(data.columns)) ? data.columns : null;
    } catch (e) {
        encColumns[table] = null;
    } finally {
        encColLoading.delete(table);
    }
    return encColumns[table];
}

function renderEncColumns(table) {
    const cols = encColumns[table];
    if (!Array.isArray(cols)) {
        return '<div class="fe-body-bar warn"><i class="bi bi-exclamation-triangle"></i> Columns for this table could not be loaded.</div>';
    }
    if (cols.length === 0) {
        return '<div class="fe-body-bar"><i class="bi bi-info-circle"></i> This table has no columns.</div>';
    }
    const rows = cols.map(col => {
        const on = encEnabled.has(feKey(table, col));
        const hint = feHint(col);
        const isId = col === 'id' || /_id$/.test(col);
        const hintChip = hint ? `<span class="fe-col-hint">${feEsc(hint)}</span>` : '';
        return `
        <div class="fe-col ${on ? 'on' : ''}" data-table="${feEsc(table)}" data-column="${feEsc(col)}">
            <span class="fe-col-ic"><i class="bi ${on ? 'bi-lock-fill' : 'bi-unlock'}"></i></span>
            <span class="fe-col-name">${feEsc(col)}</span>
            ${hintChip}
            <label class="fe-switch" data-bs-toggle="tooltip" title="${feEsc(FE_TIP.toggle)}">
                <input type="checkbox" class="fe-toggle" data-table="${feEsc(table)}" data-column="${feEsc(col)}" ${on ? 'checked' : ''} ${isId ? 'disabled' : ''}>
                <span class="fe-slider"></span>
            </label>
        </div>`;
    }).join('');
    return `<div class="fe-body-bar"><i class="bi bi-list-columns"></i> ${cols.length} column${cols.length > 1 ? 's' : ''} · switch on the ones to encrypt at rest.</div>${rows}`;
}

function bindEncColumnEvents(table) {
    const body = document.querySelector(`.fe-item[data-table="${feCssEsc(table)}"] .fe-item-body`);
    if (!body) return;
    body.querySelectorAll('.fe-toggle').forEach(t => t.addEventListener('change', () => {
        const key = feKey(t.dataset.table, t.dataset.column);
        if (t.checked) encEnabled.add(key); else encEnabled.delete(key);
        const row = t.closest('.fe-col');
        if (row) {
            row.classList.toggle('on', t.checked);
            const ic = row.querySelector('.fe-col-ic i');
            if (ic) ic.className = 'bi ' + (t.checked ? 'bi-lock-fill' : 'bi-unlock');
        }
        refreshEncBadge(table);
        refreshEncStatus();
        if (window.securityAutoSave) window.securityAutoSave();
    }));
}

function refreshEncBadge(table) {
    const badge = document.querySelector(`.fe-item[data-table="${feCssEsc(table)}"] .fe-item-head .fe-tbadge`);
    if (!badge) return;
    const n = encCount(table);
    badge.className = 'fe-tbadge' + (n ? ' active' : '');
    badge.innerHTML = n ? `<i class="bi bi-lock-fill"></i> ${n} encrypted` : 'None';
}
function refreshEncStatus() {
    const s = document.getElementById('encStatus');
    if (!s) return;
    const tables = new Set(); encEnabled.forEach(k => tables.add(k.split('|')[0]));
    s.innerHTML = `<i class="bi bi-lock"></i> ${encEnabled.size} column(s) encrypted across ${tables.size} table(s)`;
}

function collectEncPayload() {
    const keys = new Set([...encEnabled, ...encInitial]);
    const payload = [];
    keys.forEach(k => {
        const i = k.indexOf('|');
        payload.push({ table_name: k.slice(0, i), column_name: k.slice(i + 1), enabled: encEnabled.has(k) ? 1 : 0 });
    });
    return payload;
}

async function saveEncryption() {
    const btn = document.getElementById('saveEncryptionSettings');
    const prev = btn ? btn.innerHTML : '';
    if (btn) { btn.disabled = true; btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Saving…'; }
    try {
        const res = await fetch(`${baseUrl}/project/${projectSlug}/security/field-encryption`, {
            method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ settings: collectEncPayload() })
        });
        const data = await res.json();
        if (data.success) {
            encInitial = new Set(encEnabled);
            pp.dialog.toast('success', data.message || 'Field encryption saved');
        } else {
            pp.dialog.alert('Error', data.message || 'Could not save', 'error');
        }
    } catch (e) {
        console.error(e);
        pp.dialog.toast('error', 'Network error while saving');
    } finally {
        if (btn) { btn.disabled = false; btn.innerHTML = prev; }
    }
}

// One-click migration: save the current selections, then encrypt existing plaintext rows.
async function migrateEncryption() {
    let go = true;
    if (window.Swal) {
        const r = await Swal.fire({
            icon: 'question', title: 'Encrypt existing rows?',
            html: 'This saves your current selections, then encrypts the plaintext values already stored in the columns you&rsquo;ve switched on. It runs once and skips anything already encrypted.',
            showCancelButton: true, confirmButtonText: 'Save & encrypt', cancelButtonText: 'Cancel',
            confirmButtonColor: '#16a34a', reverseButtons: true
        });
        go = r.isConfirmed;
    } else {
        go = window.confirm('Encrypt existing rows now? This saves your selections and encrypts existing plaintext values.');
    }
    if (!go) return;

    const btn = document.getElementById('encMigrateBtn');
    const prev = btn ? btn.innerHTML : '';
    if (btn) { btn.disabled = true; btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Encrypting…'; }
    try {
        await saveEncryption();   // persist current toggles first, so the migration matches the screen
        const res = await fetch(`${baseUrl}/project/${projectSlug}/security/field-encryption/migrate`, {
            method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}'
        });
        const data = await res.json();
        if (data.success) pp.dialog.toast('success', data.message || 'Existing rows encrypted');
        else pp.dialog.alert('Error', data.message || 'Migration failed', 'error');
    } catch (e) {
        console.error(e);
        pp.dialog.toast('error', 'Network error during migration');
    } finally {
        if (btn) { btn.disabled = false; btn.innerHTML = prev; }
    }
}

function initEncTooltips(scope) {
    if (!window.bootstrap || !scope) return;
    scope.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
        try { bootstrap.Tooltip.getInstance(el)?.dispose(); new bootstrap.Tooltip(el, { container: 'body' }); } catch (e) {}
    });
}

function encTipsModalHtml() {
    return `
    <div class="modal fade" id="encTipsModal" tabindex="-1" aria-hidden="true">
      <div class="modal-dialog modal-lg modal-dialog-scrollable">
        <div class="modal-content">
          <div class="modal-header"><h5 class="modal-title"><i class="bi bi-lightbulb me-2"></i>Field Encryption — how it works</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
          <div class="modal-body">
            <p class="text-muted">Switching a column on marks it for <strong>encryption at rest</strong>: the app encrypts the value (AES-256) before saving and decrypts it when the record is read. Use it for the few columns that truly hold secrets.</p>
            <div class="fe-tip"><span class="fe-tip-ic good"><i class="bi bi-check-lg"></i></span><div><h6>Good candidates</h6><p>SSNs / tax IDs, card & bank numbers, API keys & tokens, passports — anything a database leak must not expose in plain text.</p></div></div>
            <div class="fe-tip"><span class="fe-tip-ic warn"><i class="bi bi-exclamation-triangle"></i></span><div><h6>Don&rsquo;t encrypt columns you search on</h6><p>${FE_TIP.search} IDs and foreign keys are disabled for that reason.</p></div></div>
            <hr>
            <h6 class="mb-1">Good to know</h6>
            <ul class="small text-muted mb-0">
                <li>It takes effect <strong>immediately in the built app</strong> — no rebuild. New saves are encrypted; the list, view, edit, print and export screens show the real value.</li>
                <li><strong>Rows that already exist stay readable as-is</strong> and are encrypted the next time that record is saved — or use <strong>Encrypt existing rows</strong> (bottom of this page) to protect them all at once.</li>
                <li>Make sure the column is <strong>wide enough for ciphertext</strong> — use <code>VARCHAR(255)</code> or <code>TEXT</code>. A too-small column will reject the save (it never corrupts data).</li>
                <li>The encryption key lives in the app&rsquo;s config (<code>PP_ENC_KEY</code>), never in the database, so a database leak alone can&rsquo;t decrypt it. <strong>Back the key up separately — losing it means losing the data.</strong></li>
                <li>For compliance (GDPR, HIPAA) keep a record of which fields are encrypted and why.</li>
            </ul>
          </div>
          <div class="modal-footer"><button class="btn btn-secondary" data-bs-dismiss="modal">Close</button></div>
        </div>
      </div>
    </div>`;
}

function injectEncStyles() {
    if (document.getElementById('feStyles')) return;
    const css = `
    .fe{max-width:1080px;margin:0 auto;padding:2px 4px 24px}
    .fe-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:11px}
    .fe-lead{flex:1;min-width:240px;display:flex;align-items:center;gap:8px;font-size:12px;color:#64748b;background:var(--bs-tertiary-bg,#f8fafc);border:1px solid var(--bs-border-color,#eef2f7);border-radius:9px;padding:7px 12px}
    .fe-lead .bi{color:#4f46e5}
    .fe-bar-actions{display:flex;gap:8px;align-items:center;margin-left:auto}
    .fe-search{display:flex;align-items:center;gap:7px;background:var(--bs-body-bg,#fff);border:1px solid var(--bs-border-color,#e2e8f0);border-radius:9px;padding:6px 10px;color:#64748b}
    .fe-search input{border:0;outline:0;background:transparent;font-size:12.5px;width:140px;color:inherit}
    .fe-btn{display:inline-flex;align-items:center;gap:7px;border-radius:9px;font-size:12.5px;font-weight:650;padding:7px 13px;cursor:pointer;border:1px solid transparent;transition:.15s}
    .fe-btn.ghost{background:var(--bs-body-bg,#fff);border-color:var(--bs-border-color,#e2e8f0);color:var(--bs-body-color,#334155)}
    .fe-btn.ghost:hover{border-color:#a5b4fc;color:#4f46e5}
    .fe-btn.primary{background:#4f46e5;color:#fff}.fe-btn.primary:hover{filter:brightness(1.08)}
    .fe-btn.primary:disabled{opacity:.7;cursor:default}
    .fe-acc{border:1px solid var(--bs-border-color,#e2e8f0);border-radius:11px;overflow:hidden;background:var(--bs-body-bg,#fff)}
    .fe-item{border:0}
    .fe-item+.fe-item{border-top:1px solid var(--bs-border-color,#eef2f7)}
    .fe-item.open{background:color-mix(in srgb,#4f46e5 4%,transparent)}
    .fe-item-head{display:flex;align-items:center;gap:10px;width:100%;border:0;background:transparent;padding:8px 13px;cursor:pointer;font:inherit;text-align:left;color:var(--bs-body-color,#0f172a);transition:background .12s}
    .fe-item-head:hover{background:var(--bs-tertiary-bg,#f6f8fc)}
    .fe-item.open .fe-item-head:hover{background:transparent}
    .fe-caret{font-size:11px;color:#94a3b8;transition:transform .18s}
    .fe-item.open .fe-caret{transform:rotate(90deg);color:#4f46e5}
    .fe-item-ic{font-size:15px;color:#4f46e5}
    .fe-item-name{font-weight:650;font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .fe-tbadge{flex:0 0 auto;font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;padding:2px 8px;border-radius:999px;background:var(--bs-tertiary-bg,#f1f5f9);color:#94a3b8;display:inline-flex;gap:4px;align-items:center}
    .fe-tbadge.active{background:#16a34a;color:#fff}
    .fe-item-body{display:none}
    .fe-item.open .fe-item-body{display:block;border-top:1px solid var(--bs-border-color,#eef2f7)}
    .fe-loading{padding:14px;color:#64748b;font-size:13px;display:flex;gap:9px;align-items:center}
    .fe-body-bar{display:flex;gap:7px;align-items:center;padding:8px 14px;font-size:11.5px;font-weight:600;color:#64748b;background:var(--bs-tertiary-bg,#fafbfe);border-bottom:1px solid var(--bs-border-color,#f1f5f9)}
    .fe-body-bar.warn{color:#b45309}
    .fe-col{display:flex;align-items:center;gap:11px;padding:8px 14px}
    .fe-col+.fe-col{border-top:1px dashed var(--bs-border-color,#eef2f7)}
    .fe-col-ic{flex:0 0 auto;width:26px;height:26px;border-radius:7px;display:grid;place-items:center;font-size:13px;color:#94a3b8;background:var(--bs-tertiary-bg,#f1f5f9)}
    .fe-col.on .fe-col-ic{color:#fff;background:#16a34a}
    .fe-col-name{flex:1;min-width:0;font-size:13px;font-weight:600;color:var(--bs-body-color,#334155);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--bs-font-monospace,monospace)}
    .fe-col-hint{flex:0 0 auto;font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;padding:2px 7px;border-radius:999px;background:#f59e0b1f;color:#b45309}
    .fe-switch{position:relative;display:inline-block;width:40px;height:23px;flex:0 0 auto;cursor:pointer;margin:0}
    .fe-switch input{position:absolute;opacity:0;width:0;height:0}
    .fe-slider{position:absolute;inset:0;border-radius:999px;background:var(--bs-border-color,#cbd5e1);transition:.18s}
    .fe-slider::before{content:"";position:absolute;left:3px;top:3px;width:17px;height:17px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:.18s}
    .fe-switch input:checked+.fe-slider{background:#16a34a}
    .fe-switch input:checked+.fe-slider::before{transform:translateX(17px)}
    .fe-switch input:disabled+.fe-slider{opacity:.45;cursor:not-allowed}
    .fe-foot{position:sticky;bottom:0;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:14px;padding:11px 4px;background:linear-gradient(transparent,var(--bs-body-bg,#fff) 40%)}
    .fe-foot-actions{display:flex;gap:8px;align-items:center}
    .fe-status{font-size:12.5px;color:#64748b;display:inline-flex;gap:7px;align-items:center}.fe-status .bi{color:#16a34a}
    .fe-empty{text-align:center;padding:38px 20px;color:#94a3b8}.fe-empty .bi{font-size:28px;opacity:.6}.fe-empty p{margin:9px 0 0;font-size:13px}
    .fe-tip{display:flex;gap:12px;padding:10px 0}
    .fe-tip-ic{flex:0 0 auto;width:36px;height:36px;border-radius:10px;display:grid;place-items:center;font-size:16px;color:#fff}
    .fe-tip-ic.good{background:#16a34a}.fe-tip-ic.warn{background:#f59e0b}
    .fe-tip h6{margin:0 0 3px;font-size:14px;font-weight:750}.fe-tip p{margin:0;font-size:12.5px;color:#64748b}
    `;
    const style = document.createElement('style');
    style.id = 'feStyles'; style.textContent = css;
    document.head.appendChild(style);
}

window.renderEncryption = renderEncryption;
