<?php

namespace UltraguardPro\modules\authenticator;

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

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

class AuthenticatorModule extends AbstractModule {

    private TwoFactorModule $two_factor;

    private PasskeysModule $passkeys;

    public function __construct( Plugin $plugin ) {
        parent::__construct( $plugin );

        $this->plugin->settings->register_module_prefix( 'two_factor_', 'two_factor' );
        $this->plugin->settings->register_module_prefix( 'passkey_', 'passkeys' );

        $this->two_factor = new TwoFactorModule( $plugin );
        $this->passkeys   = new PasskeysModule( $plugin );
    }

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

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

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

    public function boot(): void {
        $_db_tables = $this->plugin->modules->get_db_tables();
        if ( $_db_tables ) {
            $_db_tables->register_schema( new schema\AuthenticatorSchema() );
        }

        $this->maybe_register_2fa_migration_notice();

        if ( method_exists( $this->plugin->settings, 'register_settings_schema' ) ) {
            $this->plugin->settings->register_settings_schema( 'two_factor', 'two_factor_', [
                'two_factor_enabled'              => [ 'type' => 'bool', 'default' => true ],
                'two_factor_allow_self_enroll'   => [ 'type' => 'bool', 'default' => true ],
                'two_factor_required_roles'      => [ 'type' => 'array', 'default' => [], 'options' => array_keys( wp_roles()->get_names() ) ],
                'two_factor_grace_period_days'   => [ 'type' => 'int', 'default' => 7 ],
                'two_factor_show_setup_prompt'   => [ 'type' => 'bool', 'default' => true ],
                'two_factor_backup_code_count'   => [ 'type' => 'select', 'default' => '8', 'options' => [ '6', '8', '10' ] ],
                'two_factor_email_notifications' => [ 'type' => 'bool', 'default' => true ],
                'two_factor_issuer_name'         => [ 'type' => 'text', 'default' => get_bloginfo( 'name' ) ],
                'two_factor_scheduled_task'      => [ 'type' => 'bool', 'default' => false ],
                'two_factor_task_frequency'      => [ 'type' => 'select', 'default' => 'daily', 'options' => [ 'hourly', 'twicedaily', 'daily' ] ],
            ] );

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

        ( new ajax\TwoFactorAjax( $this->plugin ) )->register();
        ( new ajax\PasskeysAjax( $this->plugin ) )->register();
        ( new TwoFactorDashboardContributor( $this->plugin ) )->register();
        ( new PasskeysDashboardContributor( $this->plugin ) )->register();
        ( new TwoFactorNotifications( $this->plugin ) )->register();

        add_action( 'ultraguard_register_admin_pages', [ $this, 'register_pages' ], 56, 1 );
        add_action( 'ultraguard_after_enqueue_assets', [ $this->two_factor, 'enqueue_assets' ] );
        add_action( 'admin_enqueue_scripts', [ $this->passkeys, 'enqueue_admin_passkey_assets' ] );
        add_filter( 'ultraguard_pro/compliance/available_sections', [ $this, 'add_compliance_sections' ] );
        add_filter( 'ultraguard_pro/compliance/collect_data', [ $this, 'add_compliance_data' ], 10, 4 );

        if ( ! $this->is_preview_mode() ) {
            add_action( 'ultraguard_two_factor_cron_task', [ $this->two_factor, 'run_cron_task' ] );
            add_action( 'wp_login', [ $this->two_factor, 'intercept_login_flow' ], 10, 2 );
            add_action( 'login_form', [ $this->two_factor, 'inject_login_form_notice' ] );
            add_action( 'login_form', [ $this->passkeys, 'inject_passkey_button' ], 20 );
            add_action( 'login_form_ultraguard_2fa_verify', [ $this->two_factor, 'render_verification_ui' ] );
            add_filter( 'authenticate', [ $this->two_factor, 'validate_pending_two_factor' ], 95, 3 );
            add_action( 'show_user_profile', [ $this->two_factor, 'render_profile_controls' ] );
            add_action( 'edit_user_profile', [ $this->two_factor, 'render_profile_controls' ] );
            add_action( 'personal_options_update', [ $this->two_factor, 'save_profile_preferences' ] );
            add_action( 'edit_user_profile_update', [ $this->two_factor, 'save_profile_preferences' ] );
            add_action( 'login_enqueue_scripts', [ $this->passkeys, 'enqueue_login_assets' ] );
            add_action( 'admin_init', [ $this->passkeys, 'enforce_required_roles' ], 5 );
            add_action( 'ultraguard_pro_daily_scan', [ $this->passkeys, 'cleanup_expired_challenges' ] );
            add_action( 'wp_loaded', [ $this->two_factor, 'maybe_setup_schedule' ] );
            add_action( 'update_option_two_factor_task_frequency', [ $this->two_factor, 'reschedule_cron' ], 10, 2 );
        }

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

    public function register_pages( $admin ): void {
        $admin->register_page( [
            'id'              => 'authenticator',
            'page_title'      => __( 'Authenticator', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'Authenticator', 'ultraguard-security-suite' ),
            'capability'      => 'manage_options',
            'scheme_callback' => [ new pages\TwoFactorDashboard( $this->plugin ), 'get_scheme' ],
            'parent_id'       => '',
            'priority'        => 56,
            'group'           => 'Access Control',
            'icon'            => 'dashicons-shield-alt',
        ] );

        $admin->register_page( [
            'id'              => 'two-factor-settings',
            'page_title'      => __( 'Two-Factor Settings', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'Two-Factor Settings', 'ultraguard-security-suite' ),
            'capability'      => 'manage_options',
            'scheme_callback' => [ new pages\TwoFactorSettings( $this->plugin ), 'get_scheme' ],
            'parent_id'       => 'authenticator',
            'priority'        => 57,
            'group'           => 'Access Control',
            'icon'            => 'dashicons-admin-settings',
        ] );

        $admin->register_page( [
            'id'              => 'passkeys',
            'page_title'      => __( 'Passkeys', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'Passkeys', 'ultraguard-security-suite' ),
            'capability'      => 'read',
            'scheme_callback' => [ new pages\PasskeysDashboard( $this->plugin ), 'get_scheme' ],
            'parent_id'       => 'authenticator',
            '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' => [ new pages\PasskeysSettings( $this->plugin ), 'get_scheme' ],
            'parent_id'       => 'authenticator',
            'priority'        => 59,
            'group'           => 'Access Control',
            'icon'            => 'dashicons-lock',
        ] );
    }

    public function add_compliance_sections( array $sections ): array {
        $sections['authentication_events'] = __( 'Authentication Events', 'ultraguard-security-suite' );
        return $sections;
    }

    public function add_compliance_data( array $sections, string $type, array $options, array $meta ): array {
        $requested = isset( $options['sections'] ) && is_array( $options['sections'] ) ? $options['sections'] : [];
        if ( $requested && ! in_array( 'authentication_events', $requested, true ) ) {
            return $sections;
        }

        $totp_table     = $this->plugin->modules->get_db_tables()->get_table( 'totp_credentials' );
        $passkeys_table = $this->plugin->modules->get_db_tables()->get_table( 'passkeys' );

        $section = $sections['authentication_events'] ?? [
            'title'   => __( 'Authentication Events', 'ultraguard-security-suite' ),
            'content' => [],
        ];
        $content = is_array( $section['content'] ?? null ) ? $section['content'] : [];

        $content['authenticator'] = [
            'two_factor_enabled_users'  => $totp_table && method_exists( $totp_table, 'count_enabled_users' ) ? (int) $totp_table->count_enabled_users() : 0,
            'two_factor_enforced_users' => $totp_table && method_exists( $totp_table, 'count_enforced_users' ) ? (int) $totp_table->count_enforced_users() : 0,
            'passkeys_registered'       => $passkeys_table ? (int) $passkeys_table->count() : 0,
            'passkeys_available'        => $this->is_passkeys_available(),
        ];

        if ( $passkeys_table ) {
            $recent_passkeys = method_exists( $passkeys_table, 'get_recent' ) ? $passkeys_table->get_recent( 10 ) : $passkeys_table->get_by( [], 10, 'created_at', 'DESC' );
            $content['recent_passkeys'] = array_map( static function( array $row ): array {
                return [
                    'user_id'     => $row['user_id'] ?? '',
                    'device_name' => $row['device_name'] ?? '',
                    'last_used'   => $row['last_used'] ?? '',
                    'created_at'  => $row['created_at'] ?? '',
                ];
            }, $recent_passkeys );
        }

        $section['content']                = $content;
        $sections['authentication_events'] = $section;

        return $sections;
    }

    public function get_pending_session( string $token ): ?array {
        return $this->two_factor->get_pending_session( $token );
    }

    public function complete_pending_login( string $token, bool $remember = false ): bool {
        return $this->two_factor->complete_pending_login( $token, $remember );
    }

    public function is_passkeys_available(): bool {
        return LicenseInfo::instance()->isPro();
    }

    /**
     * Warn administrators when legacy 2FA secrets may need re-enrolment.
     */
    private function maybe_register_2fa_migration_notice(): void {
        $has_key         = (bool) get_option( 'ultraguard_2fa_encryption_key' );
        $needs_reenrol   = (bool) get_option( 'ultraguard_2fa_reenrol_required' );
        $has_credentials = $this->has_existing_2fa_credentials();

        if ( ! $has_credentials ) {
            delete_option( 'ultraguard_2fa_reenrol_required' );
            return;
        }

        if ( $has_key && ! $needs_reenrol ) {
            return;
        }

        add_action( 'admin_notices', function() {
            echo '<div class="notice notice-warning"><p>'
                . esc_html__( 'UltraGuard: 2FA encryption key has been upgraded. Existing 2FA users will need to re-enrol. Please notify your users.', 'ultraguard-security-suite' )
                . '</p></div>';
        } );
    }

    /**
     * Detect whether the TOTP credentials table already contains enrolled users.
     */
    private function has_existing_2fa_credentials(): bool {
        $table = $this->plugin->modules->get_db_tables()->get_table( 'totp_credentials' );

        return $table && method_exists( $table, 'count' ) && (int) $table->count() > 0;
    }
}
