<?php
// Root-only page: enforced by the page-permission whitelist in
// libs/permission_manager.php AND this defensive in-file gate (pages must
// never trust that they were reached through index.php alone). Delegated
// sub-users of root also carry AUTH_USER === 'root', so a real system
// session is required too.
if (!defined('AUTH_USER') || AUTH_USER !== 'root'
    || ($_SESSION['user_type'] ?? '') !== 'system') {
    echo '<div class="alert alert-danger">Root access required.</div>';
    return;
}

require_once('/docker/whp/web/libs/usermgmt.php');
require_once('/docker/whp/web/libs/user_management_actions.php');
$UserMgmt = new usermgmt();

$message = '';
$message_type = '';

// Handle form submissions (non-JS fallback; the async path posts the same
// actions to api/user-management-ajax.php via the shared handler).
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $result = whp_user_management_handle_action($UserMgmt);
    $message = $result['message'];
    $message_type = $result['type'];
}

// Get list of users
$all_users = $UserMgmt->list_users();

// Filter out system users (UID < 1000 or protected users)
$users = array_filter($all_users, function($user) {
    return $user['uid'] >= 1000 && !$user['protected'];
});
?>

<?php if (!empty($message)): ?>
<div class="row">
    <div class="col-sm-12">
        <div class="alert alert-<?php echo $message_type; ?> alert-dismissible" role="alert">
            <button type="button" class="close" data-bs-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
            <?php echo htmlspecialchars($message); ?>
        </div>
    </div>
</div>
<?php endif; ?>

<div class="row">
    <!-- Create User Panel -->
    <div class="col-md-6">
        <div class="card mb-3">
            <div class="card-header">
                <h5 class="card-title mb-0">Create New User</h5>
            </div>
            <div class="card-body">
                <form method="POST" action="" data-whp-async data-whp-action="/api/user-management-ajax.php">
                    <input type="hidden" name="action" value="create_user">
                    <input type="hidden" name="csrf_token" value="<?php echo get_csrf_token(); ?>">
                    <div class="mb-3">
                        <label for="create_username" class="form-label">Username</label>
                        <input type="text" class="form-control" id="create_username" name="username" placeholder="newuser" required>
                    </div>
                    <div class="mb-3">
                        <label for="create_password" class="form-label">Password</label>
                        <input type="password" class="form-control" id="create_password" name="password" placeholder="Secure password" required>
                    </div>
                    <div class="mb-3">
                        <label for="account_type" class="form-label">Account Type</label>
                        <select class="form-control" id="account_type" name="account_type">
                            <option value="full">Full Hosting</option>
                            <option value="domain_dns">Domain/DNS Only</option>
                            <option value="mail_dns">Mail/DNS Only</option>
                        </select>
                        <div class="form-text text-muted">Domain/DNS: domains and DNS records only. Mail/DNS: email + domains/DNS. Full: all features.</div>
                    </div>
                    <button type="submit" class="btn btn-success">Create User</button>
                </form>
            </div>
        </div>
    </div>
    
    <!-- Change Password Panel -->
    <div class="col-md-6">
        <div class="card mb-3">
            <div class="card-header">
                <h5 class="card-title mb-0">Change User Password</h5>
            </div>
            <div class="card-body">
                <form method="POST" action="" data-whp-async data-whp-action="/api/user-management-ajax.php">
                    <input type="hidden" name="action" value="change_password">
                    <input type="hidden" name="csrf_token" value="<?php echo get_csrf_token(); ?>">
                    <div class="mb-3">
                        <label for="change_username" class="form-label">Username</label>
                        <select class="form-select" id="change_username" name="username" required>
                            <option value="">Select user...</option>
                            <?php foreach ($users as $user): ?>
                            <option value="<?php echo htmlspecialchars($user['username']); ?>"><?php echo htmlspecialchars($user['username']); ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label for="change_password" class="form-label">New Password</label>
                        <input type="password" class="form-control" id="change_password" name="password" placeholder="New password" required>
                    </div>
                    <button type="submit" class="btn btn-warning">Change Password</button>
                </form>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <!-- Users List -->
    <div class="col-md-12">
        <div class="card">
            <div class="card-header">
                <h5 class="card-title mb-0">User Accounts</h5>
            </div>
            <div class="card-body">
                <table id="users-table" class="table table-striped table-hover" data-whp-table data-whp-page-size="25">
                    <?php
                    // Load account types for all users
                    $user_account_types = [];
                    require_once('/docker/whp/web/libs/mysqlmgmt.php');
                    $MySQLMgmt_list = new mysqlmgmt();
                    $list_db = $MySQLMgmt_list->getMySQLConnection();
                    if ($list_db) {
                        $stmt = $list_db->query("SELECT username, account_type FROM whp.client_allowances");
                        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
                            $user_account_types[$row['username']] = $row['account_type'] ?? 'full';
                        }
                    }
                    $type_badges = [
                        'full' => '<span class="badge bg-success">Full Hosting</span>',
                        'domain_dns' => '<span class="badge bg-primary">Domain/DNS</span>',
                        'mail_dns' => '<span class="badge" style="background-color:#6f42c1">Mail/DNS</span>',
                    ];
                    ?>
                    <thead class="table-dark">
                        <tr>
                            <th>Username</th>
                            <th>UID</th>
                            <th>Account Type</th>
                            <th>Home Directory</th>
                            <th data-whp-nosort>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($users as $user):
                            $uname = $user['username'];
                            $acct_type = $user_account_types[$uname] ?? 'full';
                            $is_whp_user = ($uname === 'whp');
                        ?>
                        <tr>
                            <td><?php echo htmlspecialchars($uname); ?></td>
                            <td><?php echo htmlspecialchars($user['uid']); ?></td>
                            <td><?php echo $type_badges[$acct_type] ?? $type_badges['full']; ?></td>
                            <td><?php echo htmlspecialchars($user['home']); ?></td>
                            <td>
                                <?php if (!$user['protected'] && $user['uid'] >= 1000): ?>
                                <div class="d-flex gap-1 align-items-center">
                                    <!-- Account Type Edit -->
                                    <form method="POST" action="" style="display:inline;" class="d-flex gap-1 align-items-center" data-whp-async data-whp-action="/api/user-management-ajax.php">
                                        <input type="hidden" name="action" value="change_account_type">
                                        <input type="hidden" name="csrf_token" value="<?php echo get_csrf_token(); ?>">
                                        <input type="hidden" name="username" value="<?php echo htmlspecialchars($uname); ?>">
                                        <select name="account_type" class="form-select form-select-sm" style="width:auto;" onchange="(this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit())"
                                                aria-label="Account type for <?php echo htmlspecialchars($uname, ENT_QUOTES); ?>">
                                            <option value="full" <?php echo $acct_type === 'full' ? 'selected' : ''; ?>>Full Hosting</option>
                                            <option value="domain_dns" <?php echo $acct_type === 'domain_dns' ? 'selected' : ''; ?>>Domain/DNS</option>
                                            <option value="mail_dns" <?php echo $acct_type === 'mail_dns' ? 'selected' : ''; ?>>Mail/DNS</option>
                                        </select>
                                    </form>
                                    <?php if (!$is_whp_user): ?>
                                    <!-- Delete (async; opens progress modal) -->
                                    <button type="button" class="btn btn-danger btn-sm whp-delete-user-btn"
                                            data-username="<?php echo htmlspecialchars($uname); ?>">Delete</button>
                                    <?php else: ?>
                                    <span class="badge bg-secondary">System</span>
                                    <?php endif; ?>
                                </div>
                                <?php else: ?>
                                <span class="text-muted">Protected</span>
                                <?php endif; ?>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<!-- ============================================================
     Async delete-user progress modal
     ============================================================ -->
<div class="modal fade" id="whpDeleteUserModal" tabindex="-1"
     data-bs-backdrop="static" data-bs-keyboard="false"
     aria-labelledby="whpDeleteUserModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="whpDeleteUserModalLabel">Deleting user...</h5>
        <button type="button" class="btn-close whp-delete-user-close" aria-label="Close" disabled></button>
      </div>
      <div class="modal-body">
        <div class="d-flex align-items-center mb-3" id="whpDeleteUserSpinner">
          <div class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></div>
          <span id="whpDeleteUserPhase">Queuing job...</span>
        </div>
        <ul class="list-group" id="whpDeleteUserEvents"></ul>
        <div class="alert alert-success mt-3 d-none" id="whpDeleteUserSummary"></div>
        <div class="alert alert-danger  mt-3 d-none" id="whpDeleteUserError"></div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary whp-delete-user-close" disabled>Close</button>
      </div>
    </div>
  </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function () {
    const STEP_LABELS = {
        validate:         'Validating user',
        valkey_disable:   'Disabling Valkey',
        teardown:         'Tearing down sites, databases, DNS, HAProxy',
        quota:            'Removing disk quota',
        mysql_top_user:   'Dropping top-level MySQL user',
        whp_account_rows: 'Removing account rows',
        userdel:          'Removing system user',
        homedir_rm:       'Removing home directory',
    };
    const STATUS_TEXT = { start: 'running', ok: 'ok', error: 'error' };
    const STATUS_BADGE_CLASS = {
        start: 'badge bg-secondary',
        ok:    'badge bg-success',
        error: 'badge bg-danger',
    };

    function csrfToken() {
        const meta = document.querySelector('meta[name="csrf-token"]');
        if (meta && meta.content) return meta.content;
        const hidden = document.querySelector('input[name="csrf_token"]');
        return hidden ? hidden.value : '';
    }

    // DOM-safe helpers — every dynamic value is set via textContent so it
    // cannot inject markup, regardless of what the JSONL stream contains.
    function el(tag, opts = {}, children = []) {
        const e = document.createElement(tag);
        if (opts.className) e.className = opts.className;
        if (opts.text != null) e.textContent = String(opts.text);
        for (const c of children) e.appendChild(c);
        return e;
    }

    function renderEvent(ev) {
        const label = STEP_LABELS[ev.step] || ev.step;
        const badgeClass = STATUS_BADGE_CLASS[ev.status] || 'badge bg-secondary';
        const badgeText  = STATUS_TEXT[ev.status]        || ev.status;

        // Build: <li><span>label[ — detail]</span><span class=badge>status</span></li>
        const li      = el('li', { className: 'list-group-item d-flex justify-content-between align-items-start' });
        const left    = el('span');
        left.appendChild(document.createTextNode(label));

        if (ev.step === 'teardown' && ev.status === 'ok') {
            const m = ev;
            const detail = el('small', {
                className: 'text-muted',
                text: ` — ${m.sites|0} site(s), ${m.databases|0} db(s), ${m.db_users|0} db user(s), ${m.domains|0} domain(s)`,
            });
            left.appendChild(detail);
            if (m.errors|0) {
                left.appendChild(el('small', {
                    className: 'text-danger',
                    text: `, ${m.errors|0} error(s)`,
                }));
            }
        } else if (ev.error) {
            left.appendChild(el('small', { className: 'text-danger', text: ' — ' + ev.error }));
        }

        li.appendChild(left);
        li.appendChild(el('span', { className: badgeClass, text: badgeText }));
        return li;
    }

    function setEvents(events) {
        const ul = document.getElementById('whpDeleteUserEvents');
        // Collapse start+ok pairs into a single line keyed by step name —
        // a later 'ok' or 'error' for the same step replaces the earlier 'start'.
        const bySt = new Map();
        for (const ev of events) {
            const prev = bySt.get(ev.step);
            if (!prev || prev.status === 'start') bySt.set(ev.step, ev);
        }
        ul.textContent = '';
        for (const ev of bySt.values()) ul.appendChild(renderEvent(ev));
    }

    function enableClose() {
        document.querySelectorAll('.whp-delete-user-close').forEach(b => b.disabled = false);
    }

    function disableClose() {
        document.querySelectorAll('.whp-delete-user-close').forEach(b => b.disabled = true);
    }

    let pollTimer = null;
    function startPoll(jobId) {
        const tick = async () => {
            try {
                const r = await fetch('/api/delete-user-ajax.php?action=status&job_id=' + encodeURIComponent(jobId), {
                    headers: { 'Accept': 'application/json' },
                });
                const j = await r.json();
                if (j.status === 'error') {
                    document.getElementById('whpDeleteUserError').classList.remove('d-none');
                    document.getElementById('whpDeleteUserError').textContent = j.message || 'Status error';
                    document.getElementById('whpDeleteUserSpinner').classList.add('d-none');
                    enableClose();
                    return;
                }
                setEvents(j.events || []);
                if (j.done) {
                    clearInterval(pollTimer);
                    document.getElementById('whpDeleteUserSpinner').classList.add('d-none');
                    const ok = (j.final_status === '0' || j.final_status === 0);
                    const s = j.summary || {};
                    if (ok) {
                        const box = document.getElementById('whpDeleteUserSummary');
                        box.textContent = '';
                        box.appendChild(el('strong', { text: `Done in ${j.duration_s ?? '?'}s.` }));
                        box.appendChild(document.createTextNode(
                            ` Removed ${s.sites|0} site(s), ${s.databases|0} database(s), ` +
                            `${s.db_users|0} db user(s), ${s.domains|0} domain(s).`
                        ));
                        if (s.errors|0) {
                            box.appendChild(document.createTextNode(' '));
                            box.appendChild(el('strong', {
                                className: 'text-danger',
                                text: `${s.errors|0} subsystem error(s) — see /var/log/whp-delete-user-${jobId}.log`,
                            }));
                        }
                        box.classList.remove('d-none');
                    } else {
                        const box = document.getElementById('whpDeleteUserError');
                        box.textContent = j.final_msg || j.error || 'Delete failed; see worker log.';
                        box.classList.remove('d-none');
                    }
                    document.getElementById('whpDeleteUserPhase').textContent = 'Done.';
                    enableClose();
                }
            } catch (e) {
                // Network blip — keep polling. If it's persistent the user
                // can close the modal manually.
                console.warn('delete-user status poll failed:', e);
            }
        };
        tick();
        pollTimer = setInterval(tick, 1500);
    }

    async function startDelete(username) {
        if (!confirm(`Delete user "${username}"? This will remove all of their sites, databases, domains, and data. This action cannot be undone.`)) {
            return;
        }
        // Reset modal state
        document.getElementById('whpDeleteUserModalLabel').textContent = `Deleting user: ${username}`;
        document.getElementById('whpDeleteUserPhase').textContent = 'Queuing job...';
        document.getElementById('whpDeleteUserSpinner').classList.remove('d-none');
        document.getElementById('whpDeleteUserEvents').innerHTML = '';
        document.getElementById('whpDeleteUserSummary').classList.add('d-none');
        document.getElementById('whpDeleteUserError').classList.add('d-none');
        disableClose();

        const modalEl = document.getElementById('whpDeleteUserModal');
        const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
        modal.show();
        // Wire close buttons to actually dismiss the modal once enabled.
        modalEl.querySelectorAll('.whp-delete-user-close').forEach(btn => {
            btn.onclick = () => {
                if (!btn.disabled) {
                    modal.hide();
                    // Refresh page so the user list reflects reality.
                    window.location.reload();
                }
            };
        });

        const fd = new FormData();
        fd.append('action', 'delete');
        fd.append('username', username);
        fd.append('csrf_token', csrfToken());
        let r, j;
        try {
            r = await fetch('/api/delete-user-ajax.php', { method: 'POST', body: fd });
            j = await r.json();
        } catch (e) {
            document.getElementById('whpDeleteUserError').textContent = 'Failed to start job: ' + e.message;
            document.getElementById('whpDeleteUserError').classList.remove('d-none');
            document.getElementById('whpDeleteUserSpinner').classList.add('d-none');
            enableClose();
            return;
        }
        if (!j || j.status !== 'ok' || !j.job_id) {
            document.getElementById('whpDeleteUserError').textContent =
                'Failed to start job: ' + (j && j.message ? j.message : `HTTP ${r.status}`);
            document.getElementById('whpDeleteUserError').classList.remove('d-none');
            document.getElementById('whpDeleteUserSpinner').classList.add('d-none');
            enableClose();
            return;
        }
        document.getElementById('whpDeleteUserPhase').textContent = `Job ${j.job_id} running...`;
        startPoll(j.job_id);
    }

    document.querySelectorAll('.whp-delete-user-btn').forEach(btn => {
        btn.addEventListener('click', () => startDelete(btn.dataset.username));
    });
});
</script>
<script src="/js/whp-table.js?v=<?php echo htmlspecialchars($whp_css_v); ?>"></script>
<script src="/js/whp-async-forms.js?v=<?php echo htmlspecialchars($whp_css_v); ?>"></script>
