<?php
/**
 * OnboardingModule — Post-activation setup wizard for UltraGuard Pro.
 *
 * Responsibilities:
 *   • Intercepts the activation-redirect transient and routes the admin to
 *     the onboarding wizard instead of the normal dashboard.
 *   • Registers the full-screen wizard admin page (no sidebar, no WP chrome
 *     except the bare admin wrapper).
 *   • Delegates all AJAX surface to OnboardingAjax.
 *   • Exposes a static helper is_complete() used by other modules / the admin
 *     class to optionally suppress notices until onboarding is done.
 *
 * Lifecycle:
 *   Boots on every request while onboarding is incomplete so the redirect
 *   guard stays active. Once complete the module becomes a no-op — it still
 *   boots (it is a core module) but registers no hooks beyond the page entry.
 *
 * Options written:
 *   ultraguard_onboarding_complete   (bool)  — set to 1 when wizard finishes.
 *   ultraguard_onboarding_step       (int)   — last completed step (1-5).
 *   ultraguard_onboarding_site_type  (string)— chosen site profile.
 *   ultraguard_onboarding_skipped_license (bool) — true when upgrade skipped.
 *
 * @package UltraguardPro\modules\onboarding
 */

namespace UltraguardPro\modules\onboarding;

use UltraguardPro\modules\core\AbstractModule;

if ( ! defined( 'ABSPATH' ) ) { exit; }

class OnboardingModule extends AbstractModule {

    // ── Constants ────────────────────────────────────────────────────────────

    /** Option key that marks the wizard as finished. */
    public const COMPLETE_OPTION  = 'ultraguard_onboarding_complete';

    /** Option key storing the last completed step (1-5). */
    public const STEP_OPTION      = 'ultraguard_onboarding_step';

    /** Transient set by lifecycle.php on plugin activation. */
    private const REDIRECT_TRANSIENT = 'ultraguard_pro_activation_redirect';

    /** Admin page slug. */
    public const PAGE_SLUG = 'ultraguard-onboarding';

    /** Nonce action for all onboarding AJAX calls. */
    public const NONCE_ACTION = 'ultraguard_admin_nonce';

    // ── AbstractModule ────────────────────────────────────────────────────────

    public function get_id(): string { return 'onboarding'; }

    protected function requires_pro(): bool { return false; }

    /** Always enabled — it is a core module. */
    public function is_enabled(): bool { return true; }

    // ── Boot ──────────────────────────────────────────────────────────────────

    public function boot(): void {

        // Register the wizard page so WP recognises the slug.
        add_action( 'admin_menu', [ $this, 'register_wizard_page' ] );

        // Intercept the activation-redirect transient.
        add_action( 'admin_init', [ $this, 'maybe_redirect_to_wizard' ] );

        // Enqueue the plugin's shared stylesheets on the wizard page.
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_wizard_assets' ] );

        // Inject the deactivation questionnaire modal on the plugins list page.
        add_action( 'admin_footer-plugins.php', [ $this, 'render_deactivation_modal' ] );

        // Register onboarding AJAX handlers.
        ( new ajax\OnboardingAjax( $this->plugin ) )->register();

        // Register deactivation questionnaire AJAX handlers.
        ( new ajax\DeactivationAjax( $this->plugin ) )->register();

        do_action( 'ultraguard_pro/onboarding/booted', $this );
    }

    /**
     * Output the deactivation questionnaire modal on wp-admin/plugins.php.
     * Fires on the admin_footer-plugins.php hook — only on that page.
     */
    public function render_deactivation_modal(): void {
        if ( ! current_user_can( 'activate_plugins' ) ) {
            return;
        }
        ( new pages\DeactivationModal( $this->plugin ) )->render();
    }

    /**
     * Enqueue the plugin's own CSS on the onboarding page.
     * The Admin class only loads assets on the dashboard hook, so we replicate
     * the same handles here for the wizard's page hook.
     *
     * @param string $hook Current admin page hook suffix.
     */
    public function enqueue_wizard_assets( string $hook ): void {
        if ( $hook !== 'admin_page_' . self::PAGE_SLUG ) {
            return;
        }

        $url = defined( 'ULTRAGUARD_PRO_URL' )     ? ULTRAGUARD_PRO_URL     : '';
        $ver = defined( 'ULTRAGUARD_PRO_VERSION' ) ? ULTRAGUARD_PRO_VERSION : '1.0.0';

        if ( empty( $url ) ) { return; }

        wp_enqueue_style( 'dashicons' );
        wp_enqueue_style( 'admin-base',       $url . 'assets/css/admin-base.css',       [],                   $ver );
        wp_enqueue_style( 'admin-components', $url . 'assets/css/admin-components.css', ['admin-base'],       $ver );
        wp_enqueue_style( 'admin-utilities',  $url . 'assets/css/admin-utilities.css',  ['admin-components'], $ver );
        wp_enqueue_style( 'admin-theme',      $url . 'assets/css/admin-theme.css',      ['admin-components'], $ver );
    }

    // ── Admin menu ────────────────────────────────────────────────────────────

    /**
     * Register a hidden admin page for the wizard.
     *
     * add_submenu_page with a null parent keeps the page accessible via its
     * URL (admin.php?page=ultraguard-onboarding) but does NOT appear in any
     * menu — the wizard is full-screen and must not show the sidebar nav item.
     */
    public function register_wizard_page(): void {
        add_submenu_page(
            '',   // empty string = hidden page (no parent menu item rendered)
            __( 'UltraGuard Setup Wizard', 'ultraguard-security-suite' ),
            __( 'Setup Wizard', 'ultraguard-security-suite' ),
            'manage_options',
            self::PAGE_SLUG,
            [ $this, 'render_wizard' ]
        );
    }

    // ── Activation redirect ───────────────────────────────────────────────────

    /**
     * If the activation transient is present and onboarding is not yet done,
     * flush the transient and redirect to the wizard.
     *
     * Guards:
     *   • Runs only for administrators.
     *   • Skips bulk-activation (activating multiple plugins at once).
     *   • Skips if already on the wizard page (prevents a redirect loop).
     *   • Skips if onboarding was already completed.
     */
    public function maybe_redirect_to_wizard(): void {
        if ( ! \UltraguardPro\ultraguard_current_user_can_manage() ) {
            return;
        }

        if ( ! get_transient( self::REDIRECT_TRANSIENT ) ) {
            return;
        }

        // Bulk-activation guard — WordPress adds activate_multiple=1 to the URL.
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        if ( isset( $_GET['activate-multi'] ) ) {
            delete_transient( self::REDIRECT_TRANSIENT );
            return;
        }

        delete_transient( self::REDIRECT_TRANSIENT );

        if ( self::is_complete() ) {
            return;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $current_page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
        if ( $current_page === self::PAGE_SLUG ) {
            return;
        }

        wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) );
        exit;
    }

    // ── Wizard renderer ───────────────────────────────────────────────────────

    /**
     * Output the full-screen wizard HTML.
     *
     * wp_kses() is deliberately NOT used here. This is plugin-generated,
     * trusted HTML, not user-supplied content. wp_kses() strips <style> and
     * <script> tags while retaining their text content, which dumps raw CSS/JS
     * as visible text onto the page. All user-supplied values inside
     * OnboardingPage are individually escaped (esc_attr, esc_html, wp_json_encode)
     * at the point of output. The manage_options capability check is the gate.
     */
    public function render_wizard(): void {
        if ( ! \UltraguardPro\ultraguard_current_user_can_manage() ) {
            wp_die( esc_html__( 'You do not have permission to access this page.', 'ultraguard-security-suite' ) );
        }

        $page = new pages\OnboardingPage( $this->plugin );
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted plugin output, see docblock.
        echo $page->render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Renderer output uses esc_* internally  // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Renderer output, escaped internally via esc_* functions
    }

    // ── Static helpers ────────────────────────────────────────────────────────

    /**
     * True once the wizard has been completed or explicitly dismissed.
     *
     * @return bool
     */
    public static function is_complete(): bool {
        return (bool) get_option( self::COMPLETE_OPTION, false );
    }

    /**
     * Mark the wizard as complete. Called by OnboardingAjax on final step.
     *
     * @return void
     */
    public static function mark_complete(): void {
        update_option( self::COMPLETE_OPTION, true );
        update_option( self::STEP_OPTION, 5 );
    }
}
