<?php
$B = htmlspecialchars(rtrim((string) ($baseUrl ?? ''), '/'));
if (!function_exists('pp_where')) {
    function pp_where(string $path, string $lang = 'php'): string {
        $l = $lang === 'js' ? 'JS' : 'PHP';
        return '<div class="help-where"><span class="help-where-tag"><i class="bi bi-geo-alt-fill"></i> Where</span>'
             . '<span class="help-where-path">' . $path . '</span>'
             . '<span class="help-where-lang ' . htmlspecialchars($lang) . '">' . $l . '</span></div>';
    }
}
?>
<h1><i class="bi bi-globe2"></i> Global events</h1>
<p class="lead">App-wide hooks that aren't tied to one table — <strong>Authentication</strong>,
<strong>Email</strong>, <strong>Application</strong> start-up, <strong>File</strong> and <strong>API</strong>. They
all live under <b>Events → Global Events</b>. Each recipe says <strong>exactly where the code goes</strong>.</p>

<h2>The global event groups</h2>
<table class="help-table">
    <thead><tr><th>Group</th><th>Events (a selection)</th><th>Use for</th></tr></thead>
    <tbody>
        <tr><td><b>Authentication</b></td><td>Before/After Login · On Login Failed · Before/After Register · After Activate · Before/After Password Reset · After Logout</td><td>Stamp last-login, block accounts, welcome flows, audit sign-ins.</td></tr>
        <tr><td><b>Email</b></td><td>Before Send Email · After Send Email · On Email Failed</td><td>Rewrite recipients, add a signature, log failures.</td></tr>
        <tr><td><b>Application</b></td><td>App Init · Before Process · Before Display · JS OnLoad · Menu Modify</td><td>Run once at start-up, share values with the page, tweak the menu.</td></tr>
        <tr><td><b>File</b></td><td>Before/After File Upload · Before File Download / Delete</td><td>Validate uploads, watermark, restrict downloads.</td></tr>
        <tr><td><b>API</b></td><td>Before API Request · After API Request · On Webhook Receive</td><td>Guard your API endpoints, react to webhooks.</td></tr>
    </tbody>
</table>

<h2>Authentication recipes</h2>

<h3>1 · Stamp the user's last-login time</h3>
<?= pp_where('Global Events → Authentication → <b>After Login</b>', 'php') ?>
<pre><code>dbExecute('UPDATE users SET last_login = ? WHERE id = ?', [now(), $user['id']]);</code></pre>

<h3>2 · Block a suspended account at login</h3>
<?= pp_where('Global Events → Authentication → <b>Before Login</b>', 'php') ?>
<pre><code>$u = dbRow('SELECT status FROM users WHERE username = ?', [$username]);
if (($u['status'] ?? '') === 'suspended') {
    return false;   // stops the login
}</code></pre>

<h3>3 · Welcome + log a new registration</h3>
<?= pp_where('Global Events → Authentication → <b>After Register</b>', 'php') ?>
<pre><code>pp_send_email($user['email'], 'Welcome!', 'Thanks for signing up, ' . $user['username'] . '.');
dbExecute('INSERT INTO signups (user_id, at) VALUES (?, ?)', [$user['id'], now()]);</code></pre>

<h3>4 · Count failed logins</h3>
<?= pp_where('Global Events → Authentication → <b>On Login Failed</b>', 'php') ?>
<pre><code>dbExecute('INSERT INTO login_failures (username, reason, at) VALUES (?,?,?)', [$username, $reason, now()]);</code></pre>

<h2>Email recipes</h2>

<h3>5 · BCC every outgoing email to an archive box</h3>
<?= pp_where('Global Events → Email → <b>Before Send Email</b>', 'php') ?>
<pre><code>$mail['bcc'] = 'archive@example.com';   // $mail is the message (by reference)</code></pre>

<h3>6 · Log delivery failures</h3>
<?= pp_where('Global Events → Email → <b>On Email Failed</b>', 'php') ?>
<pre><code>dbExecute('INSERT INTO mail_errors ("to", subject, at) VALUES (?,?,?)', [$mail['to'], $mail['subject'], now()]);</code></pre>

<h2>Application recipes</h2>

<h3>7 · Share a value with every page</h3>
<?= pp_where('Global Events → Application → <b>Before Display</b>', 'php') ?>
<pre><code>pp_set_proxy('unread', (int) dbValue('SELECT COUNT(*) FROM messages WHERE is_read = 0'));</code></pre>
<?= pp_where('any page → Client Events → <b>On Page Init</b>', 'js') ?>
<pre><code>var n = pp.getProxy('unread', 0);
if (n) pp.dialog.toast('info', n + ' unread message(s)');</code></pre>

<h3>8 · Run something once at start-up</h3>
<?= pp_where('Global Events → Application → <b>App Init</b>', 'php') ?>
<pre><code>// runs once per request, before anything else — set defaults, register helpers, etc.
if (!dbReady()) return;   // guard if the DB isn't up yet</code></pre>

<h3>9 · Global JavaScript on every page</h3>
<?= pp_where('Global Events → Application → <b>JS OnLoad</b>', 'js') ?>
<pre><code>// runs on every page load, app-wide
document.addEventListener('keydown', function (e) {
    if ((e.ctrlKey || e.metaKey) && e.key === '/') pp.dialog.toast('info', 'Keyboard shortcuts…');
});</code></pre>

<div class="help-callout help-callout-info">
    <i class="bi bi-lightbulb"></i>
    <div>Server helpers (<code>dbExecute</code>, <code>pp_send_email</code>, <code>Security::CurrentUserData</code>)
        → <a href="<?= $B ?>/help/DB">DB</a>, <a href="<?= $B ?>/help/Helpers">Helpers</a>,
        <a href="<?= $B ?>/help/Security">Security</a>. Pass values to the client with
        <code>pp_set_proxy()</code> → read them with <code>pp.getProxy()</code>. For per-table timing, see
        <a href="<?= $B ?>/help/events">the lifecycle guide</a>.</div>
</div>
