<?php
/**
 * File Path: includes/admin/class-mbs-setup-wizard.php
 *
 * MBS Setup Wizard v2 (Two-pane editorial, Variation B)
 *
 * Replaces the v1 step-link wizard with a React-mounted single-page UI.
 * The React app lives in assets/js/wizard.js and mounts into #mbs-wizard-root
 * rendered by MBS_Setup_Wizard_Render::render().
 *
 * AJAX actions registered here:
 *   mbs_wizard_save_book   — create first mbs_book post (Bug 2 fix: taxonomy)
 *   mbs_wizard_save_layout — persist layout choice (Bug 1 fix: canonical key)
 *   mbs_wizard_activate    — activate license via MBS_License_Client (Bug 3 fix)
 *   mbs_wizard_finish      — set completion user meta, dismiss wizard
 *   mbs_wizard_skip        — set skip user meta
 *   mbs_dismiss_setup_wizard — legacy AJAX kept for compat with any saved JS
 *
 * Dismissal is stored per-user in user meta (META_DONE / META_SKIP).
 * Backward compat: also checks v1 site-option DISMISSED_KEY so existing
 * users who completed the v1 wizard are not shown the v2 wizard.
 *
 * @package MyBookShowroom
 * @since   1.2.0
 */

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

// phpcs:disable WordPress.Security.NonceVerification -- nonce verified in parent class verify_save() / check_admin_referer() before $_POST access; PHPCS cannot trace cross-method nonce verification
class MBS_Setup_Wizard {

    /** User-meta key: wizard completed. */
    const META_DONE = 'mbs_setup_wizard_done';

    /** User-meta key: wizard skipped. */
    const META_SKIP = 'mbs_setup_wizard_skipped';

    /** Legacy v1 site-option key — checked for backward compat only. */
    const DISMISSED_KEY = 'mbs_setup_wizard_dismissed';

    /** Legacy v1 site-option: wizard was started (resume notice). */
    const STARTED_KEY = 'mbs_setup_wizard_started';

    /** Admin page slug. */
    const PAGE_SLUG = 'mbs-setup-wizard';

    /** Nonce action for all wizard AJAX calls. */
    const NONCE = 'mbs_setup_wizard';

    public function __construct() {
        add_action( 'admin_menu',  array( $this, 'register_page' ) );
        add_action( 'admin_init',  array( $this, 'maybe_redirect_on_activation' ) );
        add_action( 'admin_notices',         array( $this, 'maybe_show_resume_notice' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_assets' ) );

        add_action( 'wp_ajax_mbs_wizard_save_book',      array( $this, 'ajax_save_book' ) );
        add_action( 'wp_ajax_mbs_wizard_save_layout',    array( $this, 'ajax_save_layout' ) );
        add_action( 'wp_ajax_mbs_wizard_activate',       array( $this, 'ajax_activate' ) );
        add_action( 'wp_ajax_mbs_wizard_finish',         array( $this, 'ajax_finish' ) );
        add_action( 'wp_ajax_mbs_wizard_skip',           array( $this, 'ajax_skip' ) );
        // Legacy compat — v1 dismiss action still referenced in cached JS.
        add_action( 'wp_ajax_mbs_dismiss_setup_wizard',  array( $this, 'ajax_legacy_dismiss' ) );
    }

    // -------------------------------------------------------------------------
    // Asset enqueuing
    // -------------------------------------------------------------------------

    /**
     * Enqueue wizard CSS and JS only on the wizard admin page.
     *
     * Orphan submenu pages (null parent) receive hook suffix 'admin_page_{slug}'.
     * Calling here — on admin_enqueue_scripts — ensures assets load BEFORE
     * wp_head() fires, so wizard.css appears in <head> and wp-element is
     * correctly included in the dependency chain.
     *
     * @param string $hook_suffix Current admin page hook suffix.
     * @return void
     */
    public function maybe_enqueue_assets( string $hook_suffix ): void {
        if ( 'admin_page_' . self::PAGE_SLUG !== $hook_suffix ) {
            return;
        }
        self::enqueue_assets();
    }

    // -------------------------------------------------------------------------
    // Activation redirect
    // -------------------------------------------------------------------------

    /**
     * Called from the plugin activation hook to set a one-shot redirect transient.
     */
    public static function maybe_trigger_on_activation(): void {
        if ( get_option( self::DISMISSED_KEY ) ) {
            return;
        }

        $book_count = wp_count_posts( MBS_POST_TYPE );
        $total      = (int) ( $book_count->publish ?? 0 )
                    + (int) ( $book_count->draft   ?? 0 )
                    + (int) ( $book_count->private  ?? 0 );

        if ( $total > 0 ) {
            return;
        }

        set_transient( 'mbs_setup_wizard_redirect', 1, 30 );
    }

    public function maybe_redirect_on_activation(): void {
        if ( ! get_transient( 'mbs_setup_wizard_redirect' ) ) {
            return;
        }

        delete_transient( 'mbs_setup_wizard_redirect' );

        if ( isset( $_GET['activate-multi'] ) || wp_doing_ajax() ) {
            return;
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        update_option( self::STARTED_KEY, 1 );
        $_mbs_wizard_url = admin_url( 'admin.php?page=' . self::PAGE_SLUG );
        if ( ! headers_sent() ) {
            wp_safe_redirect( $_mbs_wizard_url );
            exit;
        }
        // Headers already sent (WP core early output) — JS fallback to ensure navigation.
        echo '<script>window.location.href="' . esc_js( $_mbs_wizard_url ) . '";</script>';
        exit;
    }

    // -------------------------------------------------------------------------
    // Admin page
    // -------------------------------------------------------------------------

    public function register_page(): void {
        add_submenu_page(
            null,
            __( 'MBS Setup Wizard', 'my-book-showroom' ),
            __( 'Setup Wizard', 'my-book-showroom' ),
            'manage_options',
            self::PAGE_SLUG,
            array( 'MBS_Setup_Wizard_Render', 'render' )
        );
    }

    // -------------------------------------------------------------------------
    // Resume notice
    // -------------------------------------------------------------------------

    public function maybe_show_resume_notice(): void {
        if ( get_option( self::DISMISSED_KEY ) ) {
            return;
        }

        $uid = get_current_user_id();
        if ( get_user_meta( $uid, self::META_DONE, true ) || get_user_meta( $uid, self::META_SKIP, true ) ) {
            return;
        }

        if ( ! get_option( self::STARTED_KEY ) ) {
            return;
        }

        $screen = get_current_screen();
        if ( $screen && false !== strpos( $screen->id, self::PAGE_SLUG ) ) {
            return;
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $url = admin_url( 'admin.php?page=' . self::PAGE_SLUG );
        printf(
            '<div class="notice notice-info is-dismissible"><p>%s <a href="%s">%s</a></p></div>',
            esc_html__( 'My Book Showroom setup is not complete.', 'my-book-showroom' ),
            esc_url( $url ),
            esc_html__( 'Resume Setup Wizard →', 'my-book-showroom' )
        );
    }

    // -------------------------------------------------------------------------
    // Asset enqueuing (called from render class)
    // -------------------------------------------------------------------------

    public static function enqueue_assets(): void {
        wp_enqueue_style(
            'mbs-wizard',
            MBS_ASSETS_URL . 'css/wizard.css',
            array(),
            MBS_VERSION
        );
        // R-018: load component files before the entry-point stub.
        foreach ( array( 'rail', 'previews', 'footer', 'steps', 'app' ) as $part ) {
            wp_enqueue_script(
                'mbs-wizard-' . $part,
                MBS_ASSETS_URL . 'js/wizard/wizard-' . $part . '.js',
                array( 'wp-element', 'wp-i18n' ),
                MBS_VERSION,
                true
            );
            wp_set_script_translations( 'mbs-wizard-' . $part, 'my-book-showroom', MBS_DIR . 'languages' );
        }
        wp_enqueue_script(
            'mbs-wizard',
            MBS_ASSETS_URL . 'js/wizard.js',
            array( 'wp-element', 'wp-i18n', 'mbs-wizard-rail', 'mbs-wizard-previews', 'mbs-wizard-footer', 'mbs-wizard-steps', 'mbs-wizard-app' ),
            MBS_VERSION,
            true
        );
        wp_set_script_translations( 'mbs-wizard', 'my-book-showroom', MBS_DIR . 'languages' );
        wp_enqueue_media();

        wp_localize_script( 'mbs-wizard-rail', 'MBSWizard', array(
            'ajaxUrl'      => admin_url( 'admin-ajax.php' ),
            'nonce'        => wp_create_nonce( self::NONCE ),
            'returnTo'     => admin_url( 'edit.php?post_type=' . MBS_POST_TYPE ),
            'addBookUrl'   => admin_url( 'post-new.php?post_type=' . MBS_POST_TYPE ),
            'licenseTabUrl' => admin_url( 'admin.php?page=my-book-showroom-settings&tab=license' ),
            'privacyUrl'    => MBS_PRIVACY_URL, // WO-002
            'faqUrl'        => MBS_WEBSITE_URL . '/faq.php',
            'dashboardUrl'  => admin_url( 'admin.php?page=my-book-showroom' ),
            'layouts'          => self::get_layout_options(),
            'telemetryConsent' => get_option( MBS_Telemetry::CONSENT_KEY, '' ),
        ) );
    }

    private static function get_layout_options(): array {
        return array(
            array( 'slug' => 'hero',    'name' => __( 'Hero',    'my-book-showroom' ), 'desc' => __( 'One featured book with thumbnails below.',       'my-book-showroom' ) ),
            array( 'slug' => 'grid',    'name' => __( 'Grid',    'my-book-showroom' ), 'desc' => __( 'Classic 3-column gallery. Best for catalogs.',   'my-book-showroom' ) ),
            array( 'slug' => 'card',    'name' => __( 'Card',    'my-book-showroom' ), 'desc' => __( 'Featured 2-column with buy buttons.',            'my-book-showroom' ) ),
            array( 'slug' => 'masonry', 'name' => __( 'Masonry', 'my-book-showroom' ), 'desc' => __( 'Variable-height Pinterest-style grid.',          'my-book-showroom' ) ),
            array( 'slug' => 'list',    'name' => __( 'List',    'my-book-showroom' ), 'desc' => __( 'Compact rows with cover + details.',             'my-book-showroom' ) ),
        );
    }

    // -------------------------------------------------------------------------
    // Helper: should this user see the wizard?
    // -------------------------------------------------------------------------

    public static function should_redirect( int $user_id = 0 ): bool {
        if ( ! $user_id ) {
            $user_id = get_current_user_id();
        }
        // Respect v1 site-wide dismissal.
        if ( get_option( self::DISMISSED_KEY ) ) {
            return false;
        }
        if ( get_user_meta( $user_id, self::META_DONE, true ) ) {
            return false;
        }
        if ( get_user_meta( $user_id, self::META_SKIP, true ) ) {
            return false;
        }
        return true;
    }

    // -------------------------------------------------------------------------
    // AJAX guard — shared nonce verification for all wizard AJAX handlers
    // -------------------------------------------------------------------------

    /**
     * Verify the wizard AJAX nonce.
     *
     * Must be called as the first line of every wizard AJAX handler.
     * Terminates with a -1 response on nonce failure.
     *
     * @return void
     * @since 1.2.0
     */
    private function verify_wizard_request(): void {
        check_ajax_referer( self::NONCE, '_wpnonce' );
    }

    // -------------------------------------------------------------------------
    // AJAX: save first book
    // Bug 2 fix: store author via wp_set_object_terms (taxonomy), not postmeta.
    // -------------------------------------------------------------------------

    public function ajax_save_book(): void {
        $this->verify_wizard_request();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'my-book-showroom' ) ), 403 );
        }

        $title    = sanitize_text_field( wp_unslash( $_POST['title']    ?? '' ) );
        $author   = sanitize_text_field( wp_unslash( $_POST['author']   ?? '' ) );
        $cover_id = absint( $_POST['cover_id'] ?? 0 );

        if ( empty( $title ) ) {
            wp_send_json_error( __( 'Book title is required.', 'my-book-showroom' ) );
        }

        $post_id = wp_insert_post( array(
            'post_type'   => MBS_POST_TYPE,
            'post_status' => 'publish',
            'post_title'  => $title,
        ), true );

        if ( is_wp_error( $post_id ) ) {
            wp_send_json_error( $post_id->get_error_message() );
        }

        // Bug 2 fix: author is a taxonomy term, not postmeta.
        if ( ! empty( $author ) ) {
            wp_set_object_terms( $post_id, $author, MBS_TAX_AUTHOR );
        }

        if ( $cover_id > 0 ) {
            set_post_thumbnail( $post_id, $cover_id );
        }

        wp_send_json_success( array( 'post_id' => $post_id ) );
    }

    // -------------------------------------------------------------------------
    // AJAX: save layout
    // Bug 1 fix: use canonical option key mbs_setting_formatting_default_layout.
    // -------------------------------------------------------------------------

    public function ajax_save_layout(): void {
        $this->verify_wizard_request();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( __( 'Insufficient permissions.', 'my-book-showroom' ), 403 );
        }

        $layout = sanitize_key( wp_unslash( $_POST['layout'] ?? 'grid' ) );
        $valid  = wp_list_pluck( self::get_layout_options(), 'slug' );

        if ( ! in_array( $layout, $valid, true ) ) {
            wp_send_json_error( __( 'Invalid layout.', 'my-book-showroom' ), 400 );
        }

        // Bug 1 fix: canonical key read by mbs_get_setting('formatting','default_layout').
        update_option( 'mbs_setting_formatting_default_layout', $layout );
        wp_send_json_success();
    }

    // -------------------------------------------------------------------------
    // AJAX: activate license
    // Bug 3 fix: delegate to MBS_License_Client instead of stubbing ok=true.
    // -------------------------------------------------------------------------

    public function ajax_activate(): void {
        $this->verify_wizard_request();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( __( 'Insufficient permissions.', 'my-book-showroom' ), 403 );
        }

        $key = sanitize_text_field( wp_unslash( $_POST['license'] ?? '' ) );
        if ( empty( $key ) ) {
            wp_send_json_error( __( 'License key is required.', 'my-book-showroom' ) );
        }

        $client = new \DMRS\MBS\Api\MBS_License_Client();
        $result = $client->activate( $key );

        if ( is_wp_error( $result ) ) {
            wp_send_json_error( $result->get_error_message() );
        }

        wp_send_json_success( array( 'tier' => $result['tier'] ?? 'free' ) );
    }

    // -------------------------------------------------------------------------
    // AJAX: finish wizard
    // -------------------------------------------------------------------------

    public function ajax_finish(): void {
        $this->verify_wizard_request();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'my-book-showroom' ) ), 403 );
        }

        $uid = get_current_user_id();
        update_user_meta( $uid, self::META_DONE, time() );
        delete_option( self::STARTED_KEY );

        // WO-007: save telemetry consent choice captured in wizard Step 4.
        $telemetry = sanitize_key( wp_unslash( $_POST['telemetry'] ?? '' ) );
        if ( in_array( $telemetry, array( 'opted_in', 'opted_out' ), true ) ) {
            update_option( MBS_Telemetry::CONSENT_KEY, $telemetry );
            if ( 'opted_in' === $telemetry ) {
                MBS_Telemetry::schedule_cron();
            } else {
                MBS_Telemetry::clear_cron();
            }
        }

        wp_send_json_success();
    }

    // -------------------------------------------------------------------------
    // AJAX: skip wizard
    // -------------------------------------------------------------------------

    public function ajax_skip(): void {
        $this->verify_wizard_request();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'my-book-showroom' ) ), 403 );
        }

        $uid = get_current_user_id();
        update_user_meta( $uid, self::META_SKIP, time() );
        delete_option( self::STARTED_KEY );
        // V7-E-004: Record deferred consent so the admin notice 7-day defer mechanism applies.
        if ( '' === get_option( MBS_Telemetry::CONSENT_KEY, '' ) || 'pending' === get_option( MBS_Telemetry::CONSENT_KEY ) ) {
            update_option( MBS_Telemetry::CONSENT_KEY, 'deferred', false );
            // V8-B-002: Set 7-day defer transient so notice is suppressed for a week.
            set_transient( MBS_Telemetry::DEFER_TRANSIENT, '1', 7 * DAY_IN_SECONDS );
        }
        wp_send_json_success();
    }

    // -------------------------------------------------------------------------
    // AJAX: legacy v1 dismiss (backward compat for cached browser JS)
    // -------------------------------------------------------------------------

    public function ajax_legacy_dismiss(): void {
        // V7-A-003: Only verify the v1 nonce -- self::NONCE branch is unreachable since v2 wizard uses mbs_wizard_skip instead.
        $nonce = sanitize_text_field( wp_unslash( $_POST['nonce'] ?? '' ) );
        if ( ! wp_verify_nonce( $nonce, 'mbs_dismiss_wizard' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'my-book-showroom' ) ), 403 );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 );
        }

        $uid = get_current_user_id();
        update_user_meta( $uid, self::META_SKIP, time() );
        delete_option( self::STARTED_KEY );
        wp_send_json_success();
    }
}
