<?php
/**
 * PasskeysModule - FIDO2 / WebAuthn passwordless authentication module.
 *
 * Provides:
 *   - WebAuthn credential registration and authentication
 *   - Single-use recovery codes as a fallback
 *   - Role-based enforcement (redirect to enrol before accessing wp-admin)
 *   - "Sign in with Passkey" button on the WP login page
 *   - Dashboard stat cards via PasskeysDashboardContributor
 *
 * @package UltraguardPro\modules\authenticator
 */

namespace UltraguardPro\modules\authenticator;

use UltraguardPro\modules\core\AbstractModule;
use UltraguardPro\support\LicenseInfo;

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

class PasskeysModule extends AbstractModule {

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

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

    public function boot(): void {
        // 1. Register DB schema
        $_db_tables = $this->plugin->modules->get_db_tables();
        if ( $_db_tables ) {
            $_db_tables->register_schema( new schema\PasskeysSchema() );
        }

        $this->plugin->settings->register_settings_schema( 'passkey', 'passkey_', [
            'passkey_allow_recovery_codes' => [ 'type' => 'bool',  'default' => true ],
            'passkey_required_roles'       => [
                'type'    => 'array',
                'default' => [],
                'options' => array_keys( wp_roles()->get_names() ),
            ],
        ] );

        // 2. AJAX handlers
        ( new ajax\PasskeysAjax( $this->plugin ) )->register();

        // 3. Dashboard contribution
        ( new PasskeysDashboardContributor( $this->plugin ) )->register();

        // 4. Admin pages
        add_action( 'ultraguard_register_admin_pages', [ $this, 'register_pages' ], 30, 1 );

        // 5. Login page integration
        add_action( 'login_form',    [ $this, 'inject_passkey_button' ] );
        add_action( 'login_enqueue_scripts', [ $this, 'enqueue_login_assets' ] );

        // 5b. Admin page integration (dashboard "Register New Passkey" button)
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_passkey_assets' ] );

        // 6. Role enforcement on every wp-admin request
        add_action( 'admin_init', [ $this, 'enforce_required_roles' ], 5 );

        // 7. Daily cleanup: purge expired challenges
        add_action( 'ultraguard_pro_daily_scan', [ $this, 'cleanup_expired_challenges' ] );

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

    // -------------------------------------------------------------------------
    // Page registration
    // -------------------------------------------------------------------------

    public function register_pages( $admin ): void {
        $admin->register_page( [
            'id'              => 'passkeys',
            'page_title'      => __( 'Passkeys', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'Passkeys', 'ultraguard-security-suite' ),
            'capability'      => 'read',
            'scheme_callback' => [pages\PasskeysDashboard::class, $this->plugin ],
            'is_parent'       => false,
            'parent_id'       => 'two-factor',
            'priority'        => 58,
            'group'           => 'Access Control',
            'icon'            => 'dashicons-fingerprint',
        ] );

         $admin->register_page( [
            'id'              => 'passkey-setting',
            'page_title'      => __( 'Passkeys Settings', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'Passkeys Settings', 'ultraguard-security-suite' ),
            'capability'      => 'manage_options',
            'scheme_callback' => [pages\PasskeysSettings::class, $this->plugin ],
            'is_parent'       => false,
            'parent_id'       => 'two-factor',
            'priority'        => 59,
            'group'           => 'Access Control',
            'icon'            => 'dashicons-shield',
        ] );
    }

    // -------------------------------------------------------------------------
    // Login page
    // -------------------------------------------------------------------------

    /**
     * Inject "Sign in with Passkey" button and recovery-code link below the
     * standard WordPress login form.
     */
    public function inject_passkey_button(): void {
        if ( ! LicenseInfo::instance()->isPro() ) { return; }
        $nonce = wp_create_nonce( 'ultraguard_admin_nonce' );
        ?>
        <div id="ug-passkey-login-wrap" style="margin:16px 0;text-align:center;">
            <button type="button" id="ug-passkey-login-btn"
                    style="display:inline-flex;align-items:center;gap:8px;padding:10px 20px;border:1px solid #ddd;border-radius:6px;background:#fff;font-size:14px;font-weight:600;cursor:pointer;width:100%;justify-content:center;"
                    data-nonce="<?php echo esc_attr( $nonce ); ?>">
                <span class="dashicons dashicons-fingerprint" style="font-size:18px;width:18px;height:18px;"></span>
                <?php esc_html_e( 'Sign in with Passkey', 'ultraguard-security-suite' ); ?>
            </button>
            <p style="margin:8px 0 0;font-size:12px;">
                <a href="#" id="ug-passkey-recovery-link" style="color:#646970;">
                    <?php esc_html_e( 'Use a recovery code instead', 'ultraguard-security-suite' ); ?>
                </a>
            </p>
            <div id="ug-passkey-recovery-form" style="display:none;margin-top:12px;">
                <input type="text" id="ug-passkey-recovery-input"
                       placeholder="<?php esc_attr_e( 'XXXXX-XXXXX-XXXXX-XXXXX', 'ultraguard-security-suite' ); ?>"
                       style="width:100%;padding:8px;border:1px solid #ddd;border-radius:4px;font-size:13px;">
                <button type="button" id="ug-passkey-recovery-submit"
                        style="margin-top:8px;width:100%;padding:8px;background:#2271b1;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:600;"
                        data-nonce="<?php echo esc_attr( $nonce ); ?>">
                    <?php esc_html_e( 'Verify Recovery Code', 'ultraguard-security-suite' ); ?>
                </button>
            </div>
        </div>
        <?php
    }

    public function enqueue_login_assets(): void {
        if ( ! LicenseInfo::instance()->isPro() ) { return; }
        wp_enqueue_script(
            'ultraguard-passkeys',
            defined( 'ULTRAGUARD_PRO_URL' ) ? ULTRAGUARD_PRO_URL . 'includes/modules/authenticator/assets/js/ultraguard-passkeys.js' : '',
            [ 'jquery' ],
            defined( 'ULTRAGUARD_PRO_VERSION' ) ? ULTRAGUARD_PRO_VERSION : '1.0.0',
            true
        );
        wp_localize_script( 'ultraguard-passkeys', 'ugPasskeys', [
            'ajaxurl' => self_admin_url( 'admin-ajax.php' ),
            'i18n'    => [
                'error_browser'  => __( 'Your browser does not support passkeys.', 'ultraguard-security-suite' ),
                'error_auth'     => __( 'Authentication failed. Please try again.', 'ultraguard-security-suite' ),
                'error_recovery' => __( 'Invalid recovery code. Please try again.', 'ultraguard-security-suite' ),
            ],
        ] );
    }

    /**
     * Enqueue passkeys JS on wp-admin pages so the "Register New Passkey" button works.
     *
     * The login page uses enqueue_login_assets(). This method covers the admin dashboard.
     * We load on any UltraGuard admin page to keep it scoped.
     */
    public function enqueue_admin_passkey_assets( string $hook ): void {
        if ( ! LicenseInfo::instance()->isPro() ) { return; }

        // Only load on UltraGuard admin pages (hook contains the top-level menu slug).
        if ( strpos( $hook, 'ultraguard' ) === false ) { return; }

        // Avoid double-registering if already enqueued by the login path.
        if ( wp_script_is( 'ultraguard-passkeys', 'enqueued' ) ) { return; }

        wp_enqueue_script(
            'ultraguard-passkeys',
            defined( 'ULTRAGUARD_PRO_URL' ) ? ULTRAGUARD_PRO_URL . 'includes/modules/authenticator/assets/js/ultraguard-passkeys.js' : '',
            [ 'jquery' ],
            defined( 'ULTRAGUARD_PRO_VERSION' ) ? ULTRAGUARD_PRO_VERSION : '1.0.0',
            true
        );

        // Provide ajaxurl + a fresh nonce matching the dashboard's ajax_nonce_action
        // ('ultraguard_admin_nonce'), which is what all buttons on that page send.
        wp_localize_script( 'ultraguard-passkeys', 'ugPasskeys', [
            'ajaxurl' => self_admin_url( 'admin-ajax.php' ),
            'nonce'   => wp_create_nonce( 'ultraguard_admin_nonce' ),
            'i18n'    => [
                'error_browser'  => __( 'Your browser does not support passkeys.', 'ultraguard-security-suite' ),
                'error_auth'     => __( 'Authentication failed. Please try again.', 'ultraguard-security-suite' ),
                'error_recovery' => __( 'Invalid recovery code. Please try again.', 'ultraguard-security-suite' ),
            ],
        ] );
    }

    // -------------------------------------------------------------------------
    // Role enforcement
    // -------------------------------------------------------------------------

    /**
     * Redirect users with a required role who have not enrolled a passkey.
     * Fires on admin_init priority 5.
     */
    public function enforce_required_roles(): void {
        if ( ! LicenseInfo::instance()->isPro() ) { return; }

        $required = (array) $this->option( 'passkey_required_roles', [] );
        if ( empty( $required ) ) { return; }

        $user = wp_get_current_user();
        if ( ! $user->ID ) { return; }

        if ( ! array_intersect( $user->roles, $required ) ) { return; }

        $manager     = new PasskeyManager( $this->plugin );
        $is_enrolled = $manager->is_enrolled( $user->ID );

        if ( $is_enrolled ) { return; }

        // Allow the passkeys settings page so the user can enrol
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $current_page = sanitize_key( wp_unslash( $_GET['page'] ?? '' ) );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $current_ug   = sanitize_key( wp_unslash( $_GET['ug_page'] ?? '' ) );

        if ( $current_page === 'ultraguard-security-suite-dashboard' && $current_ug === 'passkeys' ) {
            return;
        }

        wp_safe_redirect( self_admin_url( 'admin.php?page=ultraguard-security-suite-dashboard&ug_page=passkeys&notice=enroll_required' ) );
        exit;
    }

    // -------------------------------------------------------------------------
    // Cleanup
    // -------------------------------------------------------------------------

    public function cleanup_expired_challenges(): void {
        $db = $this->plugin->modules->get_db_tables();
        if ( ! $db ) { return; }
        $table = $db->get_table( 'passkey_challenges' );
        if ( $table && method_exists( $table, 'purge_expired' ) ) {
            $table->purge_expired();
        }
    }
}
