<?php
/**
 * DatabaseScannerModule — Database malware scanning feature module.
 *
 * Scans WordPress database tables for injected malicious content:
 *   - SEO spam / hidden links
 *   - Pharma hack patterns
 *   - eval() injections
 *   - Hidden zero-pixel iframes
 *   - Base64 / gzinflate obfuscated payloads
 *   - Header redirect injections
 *   - Hidden / orphaned administrator accounts
 *
 * @package UltraguardPro\modules\database_scanner
 */

namespace UltraguardPro\modules\database_scanner;

use UltraguardPro\modules\core\AbstractModule;

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

class DatabaseScannerModule extends AbstractModule {

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

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

    protected function allow_preview_mode(): 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\DatabaseScannerSchema() );
        }

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

        // 3. Register admin pages
        add_action( 'ultraguard_register_admin_pages', [ $this, 'register_pages' ], 35, 1 );

        if ( $this->is_preview_mode() ) {
            do_action( 'ultraguard_pro/database_scanner/preview_booted', $this );
            return;
        }

        // 4. Cron — run actual scan in background
        add_action( 'ultraguard_db_scanner_run_scan', [ $this, 'process_scan' ] );

        // 5. Hook into the daily scan to optionally auto-scan
        add_action( 'ultraguard_pro_daily_scan', [ $this, 'maybe_scheduled_scan' ] );

        // 6. Seed database-type signatures if not already present
        add_action( 'init', [ $this, 'maybe_seed_db_signatures' ], 6 );

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

    // ── Admin pages ────────────────────────────────────────────────────────────

    public function register_pages( $admin ): void {
        $admin->register_page( [
            'id'              => 'database-scanner',
            'page_title'      => __( 'Database Scanner', 'ultraguard-security-suite' ),
            'menu_title'      => __( 'DB Scanner', 'ultraguard-security-suite' ),
            'capability'      => 'manage_options',
            'scheme_callback' => [ pages\DatabaseScannerDashboard::class, $this->plugin ],
            'parent_id'       => 'antivirus',
            'priority'        => 8,
            'group'           => 'Detection',
        ] );
    }

    // ── Cron callbacks ─────────────────────────────────────────────────────────

    /**
     * Run the database scan. Called by the cron event 'ultraguard_db_scanner_run_scan'.
     *
     * Uses a transient lock to guard against concurrent execution.
     *
     * @param string $scan_id  Unique scan session ID passed from the AJAX handler.
     */
    public function process_scan( string $scan_id = '' ): void {
        // Cron concurrency guard
        $lock_key = 'ultraguard_db_scan_lock';
        if ( get_transient( $lock_key ) ) {
            return;
        }
        set_transient( $lock_key, 1, 10 * MINUTE_IN_SECONDS );

        if ( ! $scan_id ) {
            $scan_id = 'dbscan_' . wp_generate_uuid4();
        }

        set_transient( 'ultraguard_db_scan_status', [
            'scan_id'  => $scan_id,
            'status'   => 'running',
            'progress' => 10,
            'started'  => gmdate( 'Y-m-d H:i:s' ),
        ], HOUR_IN_SECONDS );

        try {
            $engine  = new DatabaseScannerEngine( $scan_id );
            $result  = $engine->scan_all();
            $threats = (int) ( $result['threats_found'] ?? 0 );
            $checked = (int) ( $result['total_checked']  ?? 0 );

            set_transient( 'ultraguard_db_scan_status', [
                'scan_id'       => $scan_id,
                'status'        => 'complete',
                'progress'      => 100,
                'phase'         => __( 'Scan complete', 'ultraguard-security-suite' ),
                'threats_found' => $threats,
                'total_checked' => $checked,
                'completed_at'  => gmdate( 'Y-m-d H:i:s' ),
            ], DAY_IN_SECONDS );

            if ( $threats > 0 ) {
                do_action( 'ultraguard_db_scan_threats_found', $scan_id, $result );
            }

            do_action( 'ultraguard_db_scan_complete', $scan_id, $result );

        } catch ( \Throwable $e ) {
            \UltraguardPro\core\Logger::error( '[DatabaseScannerModule] Scan failed', [
                'scan_id' => $scan_id,
                'error'   => $e->getMessage(),
            ] );

            set_transient( 'ultraguard_db_scan_status', [
                'scan_id' => $scan_id,
                'status'  => 'error',
                'error'   => $e->getMessage(),
            ], HOUR_IN_SECONDS );
        } finally {
            delete_transient( $lock_key );
            delete_transient( 'ultraguard_db_scan_running' );
        }
    }

    /**
     * Optionally run a database scan as part of the daily cron sweep.
     * Only fires if the admin has enabled scheduled DB scanning.
     */
    public function maybe_scheduled_scan(): void {
        if ( ! (bool) $this->option( 'database_scanner_scheduled', false ) ) {
            return;
        }
        $scan_id = 'scheduled_' . gmdate( 'YmdH' );
        wp_schedule_single_event( time() + 5, 'ultraguard_db_scanner_run_scan', [ $scan_id ] );
    }

    /**
     * Seed database-type malware signatures into ultraguard_malware_signatures
     * if they have not been inserted yet. Idempotent — each signature is
     * identified by a unique hash so duplicate inserts are skipped.
     */
    public function maybe_seed_db_signatures(): void {
        if ( get_option( 'ultraguard_db_signatures_seeded' ) ) {
            return;
        }

        $signatures = [
            [
                'name'        => 'spam_links',
                'type'        => 'database',
                'pattern'     => '/\bhref\s*=\s*["\'][^"\']*(?:casino|pharmacy|cialis|viagra|poker|slots|gambling|xanax|tramadol)[^"\']*["\']/i',
                'threat_level'=> 'high',
                'source'      => 'ultraguard_db',
            ],
            [
                'name'        => 'pharma_hack',
                'type'        => 'database',
                'pattern'     => '/(?:buy|cheap|discount|order)\s+(?:viagra|cialis|levitra|xanax|tramadol|ambien|phentermine)/i',
                'threat_level'=> 'high',
                'source'      => 'ultraguard_db',
            ],
            [
                'name'        => 'eval_injection',
                'type'        => 'database',
                'pattern'     => '/eval\s*\(\s*(?:base64_decode|gzinflate|str_rot13|gzuncompress|strrev|hex2bin)/i',
                'threat_level'=> 'critical',
                'source'      => 'ultraguard_db',
            ],
            [
                'name'        => 'hidden_iframe',
                'type'        => 'database',
                'pattern'     => '/<iframe[^>]+(?:width\s*=\s*["\']?0["\']?|height\s*=\s*["\']?0["\']?|style\s*=\s*["\'][^"\']*display\s*:\s*none)[^>]*>/i',
                'threat_level'=> 'critical',
                'source'      => 'ultraguard_db',
            ],
            [
                'name'        => 'base64_payload',
                'type'        => 'database',
                'pattern'     => '/(?:base64_decode|eval)\s*\(\s*["\'][A-Za-z0-9+\/]{40,}={0,2}["\']\s*\)/i',
                'threat_level'=> 'critical',
                'source'      => 'ultraguard_db',
            ],
            [
                'name'        => 'redirect_injection',
                'type'        => 'database',
                'pattern'     => '/header\s*\(\s*["\']Location\s*:/i',
                'threat_level'=> 'high',
                'source'      => 'ultraguard_db',
            ],
        ];

        $inserted = 0;
        foreach ( $signatures as $sig ) {
            $hash = hash( 'sha256', $sig['type'] . ':' . $sig['name'] );

            // Skip if already present
            if ( \UltraguardPro\core\DatabaseCrud::record_exists(
                'ultraguard_malware_signatures',
                [ 'signature_hash' => $hash ]
            ) ) {
                continue;
            }

            $result = \UltraguardPro\core\DatabaseCrud::insert_raw(
                'ultraguard_malware_signatures',
                [
                    'signature_hash' => $hash,
                    'name'           => $sig['name'],
                    'type'           => $sig['type'],
                    'pattern'        => $sig['pattern'],
                    'threat_level'   => $sig['threat_level'],
                    'is_active'      => 1,
                    'source'         => $sig['source'],
                    'hits_count'     => 0,
                ]
            );
            if ( $result ) {
                $inserted++;
            }
        }

        update_option( 'ultraguard_db_signatures_seeded', time(), false );

        if ( $inserted > 0 ) {
            \UltraguardPro\core\Logger::info(
                "[DatabaseScannerModule] Seeded {$inserted} database signatures"
            );
        }
    }
}
