<?php
if (!defined('AUTH_USER')) { header('Location: login.php'); exit(); }
$pageTitle  = 'cPanel Import Results';
$currentPage = 'cpanel-import-results';

$importId = $_GET['import_id'] ?? '';
if (!preg_match('/^import_[A-Za-z0-9]+$/', $importId)) {
    echo '<div class="alert alert-danger">Invalid import_id.</div>';
    return;
}
?>
<div class="container-fluid" data-import-id="<?= htmlspecialchars($importId) ?>">
    <div id="results-loading" class="alert alert-info">Loading import results…</div>
    <div id="results-error" class="alert alert-danger d-none"></div>

    <div id="results-body" class="d-none">
        <div class="row mb-4">
            <div class="col-md-3"><div class="card text-center"><div class="card-body"><h3 id="totals-sites">–</h3><div class="text-muted">Sites</div></div></div></div>
            <div class="col-md-3"><div class="card text-center"><div class="card-body"><h3 id="totals-databases">–</h3><div class="text-muted">Databases</div></div></div></div>
            <div class="col-md-3"><div class="card text-center"><div class="card-body"><h3 id="totals-mailboxes">–</h3><div class="text-muted">Mailboxes</div></div></div></div>
            <div class="col-md-3"><div class="card text-center"><div class="card-body"><h3 id="totals-forwarders">–</h3><div class="text-muted">Forwarders</div></div></div></div>
        </div>

        <div id="mx-panel" class="alert alert-warning d-none">
            <h6><i class="bi bi-arrow-repeat"></i> MX records were preserved</h6>
            <p class="mb-2">The imported domain(s) currently route mail to: <code id="mx-current-target">–</code>. The cPanel backup did not point at WHP's mail server. What would you like to do?</p>
            <button type="button" class="btn btn-primary btn-sm" id="mx-repoint">Repoint MX to WHP mail server</button>
            <button type="button" class="btn btn-outline-secondary btn-sm" id="mx-dismiss">Dismiss — this domain uses another mail provider</button>
        </div>
        <div id="mx-decided" class="text-muted small d-none"></div>

        <div class="card mb-4">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="mb-0">Mailboxes</h5>
                <div>
                    <button type="button" class="btn btn-sm btn-outline-secondary" id="reveal-all">Reveal all passwords</button>
                    <button type="button" class="btn btn-sm btn-outline-secondary" id="copy-csv">Copy as CSV</button>
                </div>
            </div>
            <div class="card-body p-0">
                <table class="table table-sm mb-0">
                    <thead><tr><th>Email</th><th>Quota MB</th><th>Status</th><th>Temp password</th></tr></thead>
                    <tbody id="mailbox-rows"></tbody>
                </table>
            </div>
        </div>

        <div class="card mb-4">
            <div class="card-header"><h5 class="mb-0">Forwarders</h5></div>
            <div class="card-body p-0">
                <table class="table table-sm mb-0">
                    <thead><tr><th>Source</th><th>Targets</th><th>Status</th></tr></thead>
                    <tbody id="forwarder-rows"></tbody>
                </table>
            </div>
        </div>

        <div class="card mb-4" id="db-users-card">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="mb-0">Databases &amp; Database Users</h5>
                <div>
                    <button type="button" class="btn btn-sm btn-outline-secondary" id="db-reveal-all">Reveal all passwords</button>
                    <button type="button" class="btn btn-sm btn-outline-secondary" id="db-copy-csv">Copy as CSV</button>
                </div>
            </div>
            <div class="card-body p-0">
                <div class="px-3 pt-3 small text-muted" id="db-users-empty-note" style="display:none;">No database users were created during this import.</div>
                <div class="px-3 pt-3" id="db-databases-section">
                    <h6 class="mb-2">Databases</h6>
                    <table class="table table-sm mb-3">
                        <thead><tr><th>Original name</th><th>New name</th><th>Size</th></tr></thead>
                        <tbody id="db-database-rows"></tbody>
                    </table>
                </div>
                <div class="px-3 pb-3" id="db-users-section">
                    <h6 class="mb-2">Database users</h6>
                    <p class="small text-muted mb-2">
                        Use these to update connection strings in non-WordPress applications
                        (WordPress wp-config files were rewritten automatically). Temp passwords
                        expire after 24h or when cleared via the button below.
                    </p>
                    <table class="table table-sm mb-0">
                        <thead><tr><th>Original user</th><th>New user</th><th>Host</th><th>Temp password</th><th>Has grants on</th></tr></thead>
                        <tbody id="db-user-rows"></tbody>
                    </table>
                </div>
            </div>
        </div>

        <div class="card mb-4">
            <div class="card-header"><h5 class="mb-0">Sites</h5></div>
            <div class="card-body" id="sites-databases">…</div>
        </div>

        <div class="card mb-4 d-none" id="sanitization-card">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="mb-0">Sanitization Sandbox</h5>
                <span id="sanitization-verdict-badge" class="badge"></span>
            </div>
            <div class="card-body">
                <div id="sanitization-alert" class="alert d-none"></div>
                <div class="row text-center mb-3">
                    <div class="col-3"><div class="small text-muted">Files scanned</div><div class="h5 mb-0" id="san-files-scanned">–</div></div>
                    <div class="col-3"><div class="small text-muted">Clean</div><div class="h5 mb-0 text-success" id="san-files-clean">–</div></div>
                    <div class="col-3"><div class="small text-muted">Cleaned in-place</div><div class="h5 mb-0" id="san-files-cleaned">–</div></div>
                    <div class="col-3"><div class="small text-muted">Quarantined</div><div class="h5 mb-0 text-danger" id="san-files-quarantined">–</div></div>
                </div>

                <div id="san-failed-block" class="alert alert-danger d-none">
                    <strong>Sandbox failure:</strong> <span id="san-failed-stage"></span> — <span id="san-failed-error"></span>
                </div>

                <div id="san-actions-wrap" class="mb-3 d-none">
                    <button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#san-actions-body" aria-expanded="false">
                        Show actions taken (<span id="san-actions-count">0</span>)
                    </button>
                    <div class="collapse mt-2" id="san-actions-body">
                        <table class="table table-sm">
                            <thead><tr><th>Action</th><th>Path</th><th>Signature / reason</th></tr></thead>
                            <tbody id="san-actions-rows"></tbody>
                        </table>
                    </div>
                </div>

                <div id="san-dbs-wrap" class="d-none">
                    <h6 class="mb-2">Database sanitization</h6>
                    <table class="table table-sm">
                        <thead><tr><th>Database</th><th>Engine pre</th><th>Engine post</th><th>Imported</th><th>Notes</th></tr></thead>
                        <tbody id="san-dbs-rows"></tbody>
                    </table>
                    <p class="small text-muted mb-0">
                        Databases not imported into the new server were flagged during scan
                        and left as <code>&lt;name&gt;.sql.flagged</code> in the cpmove extract
                        for manual review.
                    </p>
                </div>
            </div>
        </div>

        <div class="card mb-4">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="mb-0">Import log</h5>
                <button type="button" class="btn btn-sm btn-outline-secondary" id="log-toggle"
                        data-bs-toggle="collapse" data-bs-target="#log-body" aria-expanded="false">Show</button>
            </div>
            <div id="log-body" class="collapse">
                <pre id="import-log" class="card-body mb-0 small" style="max-height: 60vh; overflow:auto; white-space: pre-wrap;">(empty)</pre>
            </div>
        </div>

        <div id="cleared-banner" class="alert alert-secondary d-none"></div>
        <button type="button" class="btn btn-outline-danger" id="clear-credentials">I have securely stored these credentials — clear them from the server</button>
    </div>
</div>

<script>
(function () {
    const importId = document.querySelector('[data-import-id]').dataset.importId;
    const nonce = '<?= get_csrf_token() ?>';

    async function load() {
        const r = await fetch('/api/cpanel-import-summary.php?import_id=' + encodeURIComponent(importId));
        if (!r.ok) {
            const errEl = document.getElementById('results-error');
            errEl.replaceChildren();
            if (r.status === 404) {
                // The summary JSON only gets written on a successful import;
                // failed / in-progress / never-ran imports legitimately don't
                // have one. Don't bury the operator in "HTTP 404" — explain
                // and offer the log view instead.
                const h6 = document.createElement('h6');
                h6.textContent = 'No results summary available';
                errEl.appendChild(h6);
                const p = document.createElement('p');
                p.className = 'mb-2';
                p.textContent = 'This import has no results JSON. That happens when the import failed before completing, was cleaned up by the retention sweep, or never actually ran.';
                errEl.appendChild(p);
                const a = document.createElement('a');
                a.href = '?page=cpanel-import&import_id=' + encodeURIComponent(importId);
                a.className = 'btn btn-sm btn-outline-primary me-1';
                a.textContent = 'View import log';
                errEl.appendChild(a);
                const back = document.createElement('a');
                back.href = '?page=cpanel-import';
                back.className = 'btn btn-sm btn-outline-secondary';
                back.textContent = 'Back to imports';
                errEl.appendChild(back);
                errEl.classList.remove('alert-danger');
                errEl.classList.add('alert-warning');
            } else {
                errEl.textContent = 'Failed to load: HTTP ' + r.status;
            }
            errEl.classList.remove('d-none');
            document.getElementById('results-loading').classList.add('d-none');
            return;
        }
        render(await r.json());
    }

    function td(text) { const el = document.createElement('td'); el.textContent = text; return el; }

    function render(s) {
        document.getElementById('results-loading').classList.add('d-none');
        document.getElementById('results-body').classList.remove('d-none');
        document.getElementById('totals-sites').textContent      = (s.totals && s.totals.sites)      || 0;
        document.getElementById('totals-databases').textContent  = (s.totals && s.totals.databases)  || 0;
        document.getElementById('totals-mailboxes').textContent  = (s.totals && s.totals.mailboxes)  || 0;
        document.getElementById('totals-forwarders').textContent = (s.totals && s.totals.forwarders) || 0;

        const tbody = document.getElementById('mailbox-rows');
        tbody.replaceChildren();
        for (const m of (s.mailboxes || [])) {
            const tr = document.createElement('tr');
            tr.appendChild(td(m.email));
            tr.appendChild(td(String(m.quota_mb || '-')));

            // Status cell — color-coded badge + the per-row error text (if
            // any) inline below so the operator can see WHY a row failed
            // without ducking into a debug log.
            const statusTd = document.createElement('td');
            const badge = document.createElement('span');
            const sStr = String(m.status || '');
            badge.className = 'badge ' + ({
                created:  'bg-success',
                existing: 'bg-info text-dark',
                failed:   'bg-danger',
            }[sStr] || 'bg-secondary');
            badge.textContent = sStr;
            statusTd.appendChild(badge);
            if (m.error) {
                const errDiv = document.createElement('div');
                errDiv.className = 'small text-muted mt-1';
                errDiv.style.maxWidth = '320px';
                errDiv.textContent = m.error;
                statusTd.appendChild(errDiv);
            }
            tr.appendChild(statusTd);

            // Password cell — differentiates the three states:
            //   created   → masked dots + Reveal button
            //   existing  → "(kept pre-existing password)" placeholder; no
            //               temp password ever generated because the mailbox
            //               was already in Poste with its own password
            //   failed    → "(creation failed — no password)" so the operator
            //               doesn't misread "(no password)" as "successfully
            //               created with empty password"
            const pwTd = document.createElement('td');
            const pwSpan = document.createElement('code');
            let placeholder;
            if (sStr === 'existing')      placeholder = '(kept pre-existing password)';
            else if (sStr === 'failed')   placeholder = '(creation failed — no password)';
            else                          placeholder = '(no password)';
            const masked = m.temp_password ? '••••••••••••••••••••' : placeholder;
            pwSpan.textContent = masked;
            const btn = document.createElement('button');
            btn.className = 'btn btn-link btn-sm';
            btn.textContent = m.temp_password ? 'Reveal' : '';
            btn.disabled = !m.temp_password;
            btn.addEventListener('click', () => {
                pwSpan.textContent = (pwSpan.textContent === masked) ? m.temp_password : masked;
            });
            pwTd.appendChild(pwSpan);
            pwTd.appendChild(document.createTextNode(' '));
            pwTd.appendChild(btn);
            tr.appendChild(pwTd);
            tbody.appendChild(tr);
        }

        const ftbody = document.getElementById('forwarder-rows');
        ftbody.replaceChildren();
        for (const f of (s.forwarders || [])) {
            const tr = document.createElement('tr');
            tr.appendChild(td(f.source));
            tr.appendChild(td((f.targets || []).join(', ')));
            tr.appendChild(td(f.status));
            ftbody.appendChild(tr);
        }

        const dns = s.dns || {};
        const mxList = (dns.original_mx || []).map(m => m.host).filter(Boolean);
        const decided = dns.mx_repoint_action;
        if (decided) {
            const banner = document.getElementById('mx-decided');
            banner.classList.remove('d-none');
            banner.textContent = 'MX ' + decided + ' by ' + (dns.mx_repoint_actor || 'unknown') + ' at ' + (dns.mx_repoint_at || '?') + '.';
        } else if (mxList.length > 0) {
            document.getElementById('mx-panel').classList.remove('d-none');
            document.getElementById('mx-current-target').textContent = mxList.join(', ');
        }

        if (s.credentials_cleared_at) {
            const cb = document.getElementById('cleared-banner');
            cb.classList.remove('d-none');
            cb.textContent = 'Credentials cleared by ' + (s.credentials_cleared_by || '?') + ' at ' + s.credentials_cleared_at + '.';
            document.getElementById('clear-credentials').disabled = true;
        }

        const sd = document.getElementById('sites-databases');
        const list = document.createElement('ul');
        for (const site of (s.sites || [])) {
            const li = document.createElement('li');
            li.textContent = site.domain + ' → ' + (site.docroot || '') + ' (PHP ' + (site.php_version || '-') + ')';
            list.appendChild(li);
        }
        sd.replaceChildren(list);

        // Databases & Database Users panel
        const databases = Array.isArray(s.databases) ? s.databases : [];
        const dbUsers   = Array.isArray(s.mysql_users) ? s.mysql_users : [];

        const dbTbody = document.getElementById('db-database-rows');
        dbTbody.replaceChildren();
        if (databases.length) {
            document.getElementById('db-databases-section').style.display = '';
            for (const db of databases) {
                const tr = document.createElement('tr');
                tr.appendChild(td(db.original_name || '-'));
                tr.appendChild(td(db.whp_name || db.name || '-'));
                tr.appendChild(td(db.size_bytes ? (db.size_bytes + ' bytes') : '-'));
                dbTbody.appendChild(tr);
            }
        } else {
            document.getElementById('db-databases-section').style.display = 'none';
        }

        const duTbody = document.getElementById('db-user-rows');
        duTbody.replaceChildren();
        if (dbUsers.length) {
            document.getElementById('db-users-section').style.display = '';
            for (const u of dbUsers) {
                const tr = document.createElement('tr');
                tr.appendChild(td(u.original_name || '-'));
                tr.appendChild(td(u.whp_name || '-'));
                tr.appendChild(td(u.host || '%'));
                const pwTd = document.createElement('td');
                const pwSpan = document.createElement('code');
                const masked = u.temp_password ? '••••••••••••••••••••' : '(cleared)';
                pwSpan.textContent = masked;
                const btn = document.createElement('button');
                btn.className = 'btn btn-link btn-sm';
                btn.textContent = u.temp_password ? 'Reveal' : '';
                btn.disabled = !u.temp_password;
                btn.addEventListener('click', () => {
                    pwSpan.textContent = (pwSpan.textContent === masked) ? u.temp_password : masked;
                });
                pwTd.appendChild(pwSpan);
                pwTd.appendChild(document.createTextNode(' '));
                pwTd.appendChild(btn);
                tr.appendChild(pwTd);
                const grants = Array.isArray(u.databases) ? u.databases : [];
                tr.appendChild(td(grants.length ? grants.join(', ') : '(none)'));
                duTbody.appendChild(tr);
            }
        } else {
            document.getElementById('db-users-section').style.display = 'none';
        }

        if (!databases.length && !dbUsers.length) {
            document.getElementById('db-users-empty-note').style.display = '';
        } else {
            document.getElementById('db-users-empty-note').style.display = 'none';
        }

        // Sanitization Sandbox panel — populated only when the import was
        // routed through the cpanel-importer container. summary['sanitization']
        // is written by CpanelBackupImporter::maybeRunSanitizationContainer
        // via the per-import report.json the container drops into
        // /docker/whp/cpanel-importer-extract/<id>/report.json.
        const san = s.sanitization;
        if (san && typeof san === 'object') {
            document.getElementById('sanitization-card').classList.remove('d-none');

            // Verdict badge — drawn from the container's summary_for_panel
            // block; falls back to top-level status when the container
            // didn't populate the new field (older container builds).
            const sfp     = san.summary_for_panel || {};
            const verdict = (sfp.verdict || san.status || 'unknown').toString();
            const badge   = document.getElementById('sanitization-verdict-badge');
            badge.textContent = verdict;
            badge.classList.remove('bg-secondary', 'bg-success', 'bg-warning', 'bg-danger', 'text-dark');
            if (verdict === 'clean' || verdict === 'completed') {
                badge.classList.add('bg-success');
            } else if (verdict === 'auto-cleaned') {
                badge.classList.add('bg-warning', 'text-dark');
            } else if (verdict === 'refused' || verdict === 'failed') {
                badge.classList.add('bg-danger');
            } else {
                badge.classList.add('bg-secondary');
            }

            // Operator-facing alert message if the container provided one.
            const alertEl = document.getElementById('sanitization-alert');
            if (sfp.alert_message) {
                alertEl.textContent = sfp.alert_message;
                alertEl.classList.remove('d-none', 'alert-info', 'alert-warning', 'alert-danger');
                const sev = (sfp.alert_severity || 'info').toString();
                alertEl.classList.add(
                    sev === 'danger' ? 'alert-danger' :
                    sev === 'warning' ? 'alert-warning' : 'alert-info'
                );
            }

            document.getElementById('san-files-scanned').textContent     = Number(san.files_scanned     || 0);
            document.getElementById('san-files-clean').textContent       = Number(san.files_clean       || 0);
            document.getElementById('san-files-cleaned').textContent     = Number(san.files_cleaned     || 0);
            document.getElementById('san-files-quarantined').textContent = Number(san.files_quarantined || 0);

            // Failure details visible only when the container itself failed.
            if (san.status === 'failed') {
                document.getElementById('san-failed-block').classList.remove('d-none');
                document.getElementById('san-failed-stage').textContent = String(san.failed_stage || '(unspecified stage)');
                document.getElementById('san-failed-error').textContent = String(san.error || '(no error text)');
            }

            // Actions list — collapsed by default to keep noisy reports
            // (large clean tarballs can have hundreds of allowlist matches)
            // from dominating the page.
            const actions = Array.isArray(san.actions) ? san.actions : [];
            if (actions.length) {
                document.getElementById('san-actions-wrap').classList.remove('d-none');
                document.getElementById('san-actions-count').textContent = actions.length;
                const arows = document.getElementById('san-actions-rows');
                arows.replaceChildren();
                for (const a of actions) {
                    const tr = document.createElement('tr');
                    tr.appendChild(td(a.action || a.kind || '-'));
                    tr.appendChild(td(a.path || a.file || '-'));
                    tr.appendChild(td(a.signature || a.reason || a.detail || ''));
                    arows.appendChild(tr);
                }
            }

            // Per-database engine-swap + skip flags. The container marks
            // refused DBs with imported_into_new_server=false and renames
            // the dump <name>.sql -> <name>.sql.flagged for review.
            const sdbs = Array.isArray(san.databases) ? san.databases : [];
            if (sdbs.length) {
                document.getElementById('san-dbs-wrap').classList.remove('d-none');
                const drows = document.getElementById('san-dbs-rows');
                drows.replaceChildren();
                for (const db of sdbs) {
                    const tr = document.createElement('tr');
                    tr.appendChild(td(db.name || db.database || '-'));
                    tr.appendChild(td(db.engine_pre  || '-'));
                    tr.appendChild(td(db.engine_post || '-'));
                    const imported = (db.imported_into_new_server !== false);
                    const impTd = td(imported ? 'yes' : 'no — flagged');
                    if (!imported) impTd.className = 'text-danger fw-semibold';
                    tr.appendChild(impTd);
                    tr.appendChild(td(db.notes || db.reason || ''));
                    drows.appendChild(tr);
                }
            }
        }

        const logEl = document.getElementById('import-log');
        const logLines = Array.isArray(s.log) ? s.log : [];
        if (logLines.length) {
            logEl.textContent = logLines.join('\n');
            const toggle = document.getElementById('log-toggle');
            toggle.textContent = 'Show (' + logLines.length + ' lines)';
        } else {
            logEl.textContent = '(no log entries)';
        }
    }

    document.getElementById('reveal-all').addEventListener('click', () => {
        document.querySelectorAll('#mailbox-rows code').forEach(code => {
            const btn = code.parentElement.querySelector('button');
            if (btn && !btn.disabled && code.textContent.includes('•')) btn.click();
        });
    });

    document.getElementById('copy-csv').addEventListener('click', async () => {
        const rows = [['email', 'quota_mb', 'status', 'temp_password']];
        document.querySelectorAll('#mailbox-rows tr').forEach(tr => {
            const cells = tr.querySelectorAll('td');
            if (cells.length === 4) {
                const code = cells[3].querySelector('code');
                const pw = (code && !code.textContent.includes('•')) ? code.textContent : '(masked — reveal first)';
                rows.push([cells[0].textContent, cells[1].textContent, cells[2].textContent, pw]);
            }
        });
        const csv = rows.map(r => r.map(c => '"' + String(c).replace(/"/g, '""') + '"').join(',')).join('\n');
        await navigator.clipboard.writeText(csv);
    });

    // DB-user reveal-all + copy-CSV mirror the mailbox panel. Both share the
    // single "I have stored these credentials" clear button below — clearing
    // zeroes mailboxes and mysql_users in one summary write (see
    // CpanelImportSummary::clearCredentials).
    document.getElementById('db-reveal-all').addEventListener('click', () => {
        document.querySelectorAll('#db-user-rows code').forEach(code => {
            const btn = code.parentElement.querySelector('button');
            if (btn && !btn.disabled && code.textContent.includes('•')) btn.click();
        });
    });

    document.getElementById('db-copy-csv').addEventListener('click', async () => {
        const rows = [['original_user', 'new_user', 'host', 'temp_password', 'has_grants_on']];
        document.querySelectorAll('#db-user-rows tr').forEach(tr => {
            const cells = tr.querySelectorAll('td');
            if (cells.length === 5) {
                const code = cells[3].querySelector('code');
                const pw = (code && !code.textContent.includes('•')) ? code.textContent : '(masked — reveal first)';
                rows.push([
                    cells[0].textContent,
                    cells[1].textContent,
                    cells[2].textContent,
                    pw,
                    cells[4].textContent,
                ]);
            }
        });
        const csv = rows.map(r => r.map(c => '"' + String(c).replace(/"/g, '""') + '"').join(',')).join('\n');
        await navigator.clipboard.writeText(csv);
    });

    document.getElementById('clear-credentials').addEventListener('click', async () => {
        if (!confirm('Clear all temp passwords from the server? This cannot be undone.')) return;
        const r = await fetch('/api/cpanel-import-clear-credentials.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-Token': nonce},
            body: new URLSearchParams({import_id: importId}),
        });
        if (r.ok) location.reload();
        else alert('Failed: HTTP ' + r.status);
    });

    document.getElementById('mx-repoint').addEventListener('click', () => mxAction('repoint'));
    document.getElementById('mx-dismiss').addEventListener('click', () => mxAction('dismiss'));
    async function mxAction(action) {
        const r = await fetch('/api/cpanel-import-mx-action.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-Token': nonce},
            body: new URLSearchParams({import_id: importId, action: action}),
        });
        if (r.ok) location.reload();
        else alert('Failed: HTTP ' + r.status);
    }

    load();
})();
</script>
