<?php
declare(strict_types=1);

class ImpersonatePlugin
{
    public function register(): void
    {
        // ── Routes ───────────────────────────────────────────────────────────────
        PluginManager::addRoute('/admin/impersonate/stop', fn() => self::stop());
        // POST-only: a GET-reachable impersonate endpoint is CSRF-vulnerable to
        // top-level navigation (SameSite=Lax sends the session cookie on link
        // clicks), so a phishing link could swap the admin's identity. The
        // form in admin_user_actions submits a CSRF token along with the
        // target user id.
        PluginManager::addDynamicRoute(
            '#^/admin/impersonate/(\d+)$#',
            fn($m) => self::start((int)$m[1])
        );

        // ── Layout banner when impersonating ─────────────────────────────────────
        PluginManager::on('layout_banner', function (): void {
            if (!self::isActive()) return;
            $db       = Database::getInstance();
            $original = $db->fetch('SELECT username FROM users WHERE id = ?', [$_SESSION['_impersonate_original_id']]);
            $target   = $db->fetch('SELECT username FROM users WHERE id = ?', [$_SESSION['user_id']]);
            if (!$target) return;
            ?>
            <div class="impersonate-banner">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>
                Du siehst die App als <strong><?= htmlspecialchars($target['username'], ENT_QUOTES) ?></strong>
                <form method="POST" action="/admin/impersonate/stop" style="display:inline">
                    <?= Helper::csrf() ?>
                    <button type="submit" class="impersonate-stop-btn">
                        ← Zurück als <?= htmlspecialchars($original['username'] ?? 'Admin', ENT_QUOTES) ?>
                    </button>
                </form>
            </div>
            <?php
        });

        // ── Button in admin user table ────────────────────────────────────────────
        PluginManager::on('admin_user_actions', function (array $u): void {
            if (self::isActive()) return;
            if (!Auth::isAdmin()) return;
            if ($u['id'] === Auth::id()) return;
            if ($u['role'] === 'admin') return;
            ?>
            <form method="POST" action="/admin/impersonate/<?= (int)$u['id'] ?>" style="display:inline">
                <?= Helper::csrf() ?>
                <button type="submit"
                        class="btn btn-ghost btn-xs" data-confirm-click="Als <?= Helper::e($u['username']) ?> anmelden?"
                        title="Als diesen Nutzer anmelden">
                    Imitieren
                </button>
            </form>
            <?php
        });
    }

    // ── Actions ──────────────────────────────────────────────────────────────────

    public static function start(int $targetId): void
    {
        if (!Auth::check() || self::isActive()) {
            Helper::redirect('/dashboard');
            return;
        }
        if (!Auth::isAdmin()) {
            Helper::redirect('/dashboard', ['error' => 'access_denied']);
            return;
        }
        if (!Helper::isPost()) {
            Helper::redirect('/admin/users');
            return;
        }
        Helper::verifyCsrf();

        $db     = Database::getInstance();
        $target = $db->fetch('SELECT * FROM users WHERE id = ? AND is_active = 1', [$targetId]);

        if (!$target || $target['role'] === 'admin' || $target['id'] === Auth::id()) {
            Helper::redirect('/admin/users');
            return;
        }

        $originalAdminId = Auth::id();
        // Regenerate the session ID before swapping identity. Defends against
        // session-fixation: a session that may have been observed pre-impersonate
        // can no longer be reused as the impersonated user.
        session_regenerate_id(true);
        $_SESSION['_impersonate_original_id'] = $originalAdminId;
        $_SESSION['user_id'] = $targetId;
        $_SESSION['lang']    = $target['language'] ?? 'de';
        $_SESSION['theme']   = $target['theme'] ?? 'light';
        Auth::stampSessionLogin();

        SecurityLog::log('impersonate_start', SecurityLog::SEV_CRITICAL, ['target_user_id' => $targetId], $originalAdminId);
        Helper::redirect('/dashboard');
    }

    public static function stop(): void
    {
        if (!self::isActive()) {
            Helper::redirect('/dashboard');
            return;
        }
        if (!Helper::isPost()) {
            Helper::redirect('/dashboard');
            return;
        }
        Helper::verifyCsrf();

        $originalId = (int)$_SESSION['_impersonate_original_id'];
        unset($_SESSION['_impersonate_original_id']);

        $db    = Database::getInstance();
        $admin = $db->fetch('SELECT language, theme FROM users WHERE id = ?', [$originalId]);

        $impersonatedId = (int)($_SESSION['user_id'] ?? 0);
        // Regenerate the session ID on swap-back too, symmetrical with start().
        session_regenerate_id(true);
        $_SESSION['user_id'] = $originalId;
        $_SESSION['lang']    = $admin['language'] ?? 'de';
        $_SESSION['theme']   = $admin['theme'] ?? 'light';
        Auth::stampSessionLogin();

        SecurityLog::log('impersonate_stop', SecurityLog::SEV_INFO, ['was_user_id' => $impersonatedId], $originalId);
        Helper::redirect('/admin/users');
    }

    public static function isActive(): bool
    {
        return isset($_SESSION['_impersonate_original_id']);
    }
}
