<?php
/**
 * Spam Alert Monitor for BoostBot.
 *
 * Detects suspicious chat abuse patterns (visitors repeatedly hitting
 * hourly/daily message limits) and alerts the site administrator via
 * email and WordPress admin notices.
 *
 * Follows the same pattern as BoostBot_Low_Credits_Monitor.
 *
 * @package BoostBot
 * @since   1.20.0
 */

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

class BoostBot_Spam_Alert_Monitor {

    /**
     * Number of hourly-limit hits within 24 h to flag as suspicious.
     */
    const SPAM_THRESHOLD = 3;

    /** Transient: global flag that at least one spam alert is active. */
    const TRANSIENT_ALERT_ACTIVE = 'boostbot_spam_alert_active';

    /** Transient: admin dismissed the notice (24-hour cooldown). */
    const TRANSIENT_DISMISSED = 'boostbot_spam_notice_dismissed';

    /* ──────────────────────────────────────────────────────────────── */
    /*  Bootstrap                                                       */
    /* ──────────────────────────────────────────────────────────────── */

    /**
     * Register all hooks.
     */
    public static function init() {
        // Admin notice.
        add_action( 'admin_notices', array( __CLASS__, 'maybe_show_notice' ) );

        // AJAX handler to dismiss the notice.
        add_action( 'wp_ajax_boostbot_dismiss_spam_alert', array( __CLASS__, 'ajax_dismiss' ) );
    }

    /* ──────────────────────────────────────────────────────────────── */
    /*  Public API — called from Message Limiter / endpoint code       */
    /* ──────────────────────────────────────────────────────────────── */

    /**
     * Record that a visitor has hit a message limit.
     *
     * Should be called every time a visitor is blocked by the hourly
     * or daily message cap. Evaluates whether the pattern is suspicious
     * and triggers an alert if so.
     *
     * @param string $identifier  Visitor identifier (IP+UA hash).
     * @param string $limit_type  'hourly' | 'daily'.
     */
    public static function on_limit_hit( $identifier, $limit_type ) {
        if ( ! (bool) BoostBot_Settings::get( 'spam_alert_enabled', true ) ) {
            return;
        }

        $hash = substr( md5( $identifier ), 0, 12 );

        // Record this hit timestamp.
        $key  = 'boostbot_spam_hits_' . $hash;
        $hits = get_transient( $key );

        if ( ! is_array( $hits ) ) {
            $hits = [];
        }

        $now = time();
        $hits[] = [
            'time' => $now,
            'type' => $limit_type,
        ];

        // Keep only last 24 hours of hits.
        $cutoff = $now - 86400;
        $hits   = array_values( array_filter( $hits, function ( $hit ) use ( $cutoff ) {
            return $hit['time'] >= $cutoff;
        } ) );

        set_transient( $key, $hits, 86400 );

        // Count hourly-limit hits in the last 24 h.
        $hourly_hits = array_filter( $hits, function ( $hit ) {
            return $hit['type'] === 'hourly';
        } );

        if ( count( $hourly_hits ) >= self::SPAM_THRESHOLD ) {
            self::trigger_alert( $identifier, $hash, count( $hourly_hits ), count( $hits ) );
        }

        // Daily limit hit is inherently suspicious (200 msgs in one day).
        if ( $limit_type === 'daily' ) {
            self::trigger_alert( $identifier, $hash, count( $hourly_hits ), count( $hits ) );
        }
    }

    /* ──────────────────────────────────────────────────────────────── */
    /*  Alert trigger                                                   */
    /* ──────────────────────────────────────────────────────────────── */

    /**
     * Trigger a spam alert (email + admin notice).
     *
     * @param string $identifier     Full visitor identifier.
     * @param string $hash           Short hash (12 chars).
     * @param int    $hourly_hits    How many times the hourly limit was hit.
     * @param int    $total_hits     Total limit hits in last 24 h.
     */
    private static function trigger_alert( $identifier, $hash, $hourly_hits, $total_hits ) {
        // Set the global flag so the admin notice appears.
        set_transient( self::TRANSIENT_ALERT_ACTIVE, [
            'hash'        => $hash,
            'hourly_hits' => $hourly_hits,
            'total_hits'  => $total_hits,
            'time'        => time(),
        ], 86400 );

        // Clear previous dismissal so the notice shows again.
        delete_transient( self::TRANSIENT_DISMISSED );

        // Send email (rate-limited: 1 per visitor per 24 h).
        $email_enabled = (bool) BoostBot_Settings::get( 'spam_alert_email_enabled', true );
        $email_sent_key = 'boostbot_spam_email_sent_' . $hash;

        if ( $email_enabled && ! get_transient( $email_sent_key ) ) {
            self::send_email( $hash, $hourly_hits, $total_hits );
            set_transient( $email_sent_key, 1, 86400 );
        }

        // Log it.
        if ( class_exists( 'BoostBot_Logger' ) ) {
            BoostBot_Logger::warning( 'Spam alert triggered', [
                'visitor'     => $hash . '...',
                'hourly_hits' => $hourly_hits,
                'total_hits'  => $total_hits,
            ] );
        }
    }

    /* ──────────────────────────────────────────────────────────────── */
    /*  Email                                                           */
    /* ──────────────────────────────────────────────────────────────── */

    /**
     * Send a spam alert email to the site admin.
     *
     * @param string $hash         Visitor short hash.
     * @param int    $hourly_hits  Number of hourly-limit hits.
     * @param int    $total_hits   Total limit hits in 24 h.
     */
    private static function send_email( $hash, $hourly_hits, $total_hits ) {
        $admin_email = get_option( 'admin_email' );
        if ( empty( $admin_email ) ) {
            return;
        }

        $site_name = get_bloginfo( 'name' );
        $subject   = sprintf(
            /* translators: 1: site name */
            __( '[%s] התראת ספאם: משתמש חשוד ב-BoostBot', 'boostbot' ),
            $site_name
        );

        $hour_limit = absint( BoostBot_Settings::get( 'visitor_messages_per_hour', 50 ) );
        $day_limit  = absint( BoostBot_Settings::get( 'visitor_messages_per_day', 200 ) );

        $body = implode( "\n", [
            sprintf( 'שלום מנהל %s,', $site_name ),
            '',
            'מערכת BoostBot זיהתה דפוס שימוש חשוד בצ\'אטבוט באתר שלך.',
            '',
            sprintf( '  מזהה מבקר: %s...', $hash ),
            sprintf( '  פגיעות במגבלת שעתית (ב-24 שעות): %d פעמים', $hourly_hits ),
            sprintf( '  סה"כ פגיעות במגבלות (ב-24 שעות): %d פעמים', $total_hits ),
            '',
            sprintf( '  מגבלת הודעות שעתית: %d', $hour_limit ),
            sprintf( '  מגבלת הודעות יומית: %d', $day_limit ),
            '',
            'ייתכן שמשתמש זה מנסה לצרוך קרדיטים בכוונה או להשתמש לרעה בצ\'אטבוט.',
            '',
            sprintf( 'ניתן לשנות את מגבלות ההודעות בהגדרות: %s', admin_url( 'admin.php?page=boostbot#/settings' ) ),
            '',
            'בברכה,',
            'BoostBot',
            '',
            '---',
            sprintf( 'ניתן לבטל התראות ספאם באימייל בהגדרות: %s', admin_url( 'admin.php?page=boostbot#/settings' ) ),
        ] );

        wp_mail( $admin_email, $subject, $body );
    }

    /* ──────────────────────────────────────────────────────────────── */
    /*  Admin notice                                                    */
    /* ──────────────────────────────────────────────────────────────── */

    /**
     * Show a dismissible admin notice when a spam pattern is detected.
     */
    public static function maybe_show_notice() {
        if ( ! (bool) BoostBot_Settings::get( 'spam_alert_enabled', true ) ) {
            return;
        }

        // Check if dismissed recently.
        if ( get_transient( self::TRANSIENT_DISMISSED ) ) {
            return;
        }

        $alert = get_transient( self::TRANSIENT_ALERT_ACTIVE );
        if ( ! is_array( $alert ) ) {
            return;
        }

        // Only show on BoostBot admin pages or the WP dashboard.
        $screen = get_current_screen();
        if ( $screen && ! in_array( $screen->id, [ 'dashboard', 'toplevel_page_boostbot' ], true ) ) {
            return;
        }

        $hash        = isset( $alert['hash'] ) ? esc_html( $alert['hash'] ) : '???';
        $hourly_hits = isset( $alert['hourly_hits'] ) ? absint( $alert['hourly_hits'] ) : 0;
        $settings_url = admin_url( 'admin.php?page=boostbot#/settings' );

        printf(
            '<div class="notice notice-error is-dismissible" id="boostbot-spam-alert-notice" data-nonce="%s">'
            . '<p><strong>BoostBot — התראת ספאם:</strong> '
            . 'זוהה משתמש חשוד (מזהה: <code>%s...</code>) שפגע במגבלת ההודעות השעתית <strong>%d</strong> פעמים ב-24 שעות. '
            . 'ייתכן ניסיון לצרוך קרדיטים בכוונה. '
            . '<a href="%s">שנו הגדרות מגבלות</a>'
            . '</p></div>',
            esc_attr( wp_create_nonce( 'boostbot_dismiss_spam_alert' ) ),
            esc_html( $hash ),
            absint( $hourly_hits ),
            esc_url( $settings_url )
        );
    }

    /**
     * AJAX handler: dismiss the notice for 24 hours.
     */
    public static function ajax_dismiss() {
        check_ajax_referer( 'boostbot_dismiss_spam_alert' );
        set_transient( self::TRANSIENT_DISMISSED, 1, DAY_IN_SECONDS );
        wp_send_json_success();
    }
}
