<?php
/**
 * Email Alert Hooks — Phase 3
 *
 * Hooks into WordPress and VMPFence custom actions to fire email alerts
 * for the 14 new alert types. Each hook checks its toggle via
 * VMPFence_Email_Service::is_alert_enabled() before sending.
 *
 * Register by calling VMPFence_Email_Alert_Hooks::init() during plugin bootstrap.
 *
 * @package    VMPFence
 * @subpackage Includes
 * @since      2.2.6
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class VMPFence_Email_Alert_Hooks {

    /**
     * Register all alert hooks. Call once during plugin init.
     *
     * @since 2.2.6
     * @return void
     */
    public static function init() {
        // Requires updated VMPFence_Email_Service with is_alert_enabled() (added in 2.2.6).
        // Prevents fatal error if plugin files are partially updated.
        if (!class_exists('VMPFence_Email_Service') || !method_exists('VMPFence_Email_Service', 'is_alert_enabled')) {
            return;
        }

        // WordPress core hooks
        // Priority 8: must run BEFORE class-2fa-enforcement (priority 11) which
        // calls exit; on forced 2FA setup redirect, killing all later hooks.
        add_action('wp_login',                     array(__CLASS__, 'on_login'), 8, 2);
        add_action('retrieve_password',            array(__CLASS__, 'on_password_reset_request'), 20, 1);
        add_action('automatic_updates_complete',   array(__CLASS__, 'on_auto_update'), 20, 1);

        // VMPFence custom hooks
        add_action('vmpfence_brute_force_lockout', array(__CLASS__, 'on_account_lockout'), 20, 4);
        add_action('vmpfence_ip_blocked',          array(__CLASS__, 'on_ip_blocked'), 20, 3);
        add_action('vmpfence_config_changed',      array(__CLASS__, 'on_config_changed'), 20, 3);

        // Plugin deactivation — must be registered on the specific plugin file
        register_deactivation_hook(
            VMPFENCE_PLUGIN_DIR . 'vmpfence.php',
            array(__CLASS__, 'on_plugin_deactivated')
        );
    }

    // =====================================================================
    // LOGIN ALERTS (admin_login, admin_new_device_login, user_login, user_new_device_login)
    // =====================================================================

    /**
     * Fires on wp_login. Routes to admin or user login alert based on role.
     * Also checks for new device (IP-based MVP detection).
     *
     * @since 2.2.6
     * @param string   $user_login  The username.
     * @param \WP_User $user        The user object.
     */
    public static function on_login($user_login, $user) {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }

        $is_admin = in_array('administrator', (array) $user->roles, true);
        $login_ip = self::get_client_ip();
        $is_new_device = self::is_new_device_ip($user->ID, $login_ip);
        $login_at = current_time('Y-m-d H:i:s');

        $context = array(
            'username'   => $user_login,
            'login_ip'   => $login_ip,
            'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '',
            'login_at'   => $login_at,
            'country'    => self::get_ip_country($login_ip),
        );

        if ($is_admin) {
            if ($is_new_device) {
                $context['device_info'] = self::get_device_summary($context['user_agent']);
                $context['is_new_ip']   = true;
                if (VMPFence_Email_Service::is_alert_enabled('admin_new_device_login')) {
                    VMPFence_Email_Service::send_alert('admin_new_device_login', $context);
                    // Record the new IP so we don't alert again
                    self::record_login_ip($user->ID, $login_ip);
                    return; // new-device alert supersedes regular login alert
                }
            }
            // If email_admin_new_device_only is enabled, skip alert for known devices
            $new_device_only = (int) VMPFence_Config::get('email_admin_new_device_only', 0);
            if ($new_device_only && !$is_new_device) {
                // Known device — suppress admin_login alert when modifier is ON
            } elseif (VMPFence_Email_Service::is_alert_enabled('admin_login')) {
                VMPFence_Email_Service::send_alert('admin_login', $context);
            }
        } else {
            $context['user_role'] = !empty($user->roles) ? ucfirst($user->roles[0]) : 'Subscriber';

            if ($is_new_device) {
                $context['device_info'] = self::get_device_summary($context['user_agent']);
                $context['is_new_ip']   = true;
                if (VMPFence_Email_Service::is_alert_enabled('user_new_device_login')) {
                    VMPFence_Email_Service::send_alert('user_new_device_login', $context);
                    self::record_login_ip($user->ID, $login_ip);
                    return;
                }
            }
            if (VMPFence_Email_Service::is_alert_enabled('user_login')) {
                VMPFence_Email_Service::send_alert('user_login', $context);
            }
        }

        // Always record for future new-device detection
        self::record_login_ip($user->ID, $login_ip);
    }

    // =====================================================================
    // PASSWORD RESET ALERT
    // =====================================================================

    /**
     * Fires on retrieve_password (password reset request).
     *
     * @since 2.2.6
     * @param string $user_login  The username requesting reset.
     */
    public static function on_password_reset_request($user_login) {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('password_reset')) {
            return;
        }

        $user = get_user_by('login', $user_login);
        $context = array(
            'username'     => $user_login,
            'user_email'   => $user ? $user->user_email : '',
            'user_role'    => ($user && !empty($user->roles)) ? ucfirst($user->roles[0]) : '',
            'requested_ip' => self::get_client_ip(),
            'requested_at' => current_time('Y-m-d H:i:s'),
        );

        VMPFence_Email_Service::send_alert('password_reset', $context);
    }

    // =====================================================================
    // AUTO-UPDATE ALERT
    // =====================================================================

    /**
     * Fires on automatic_updates_complete.
     *
     * @since 2.2.6
     * @param array $results  Update results from WordPress.
     */
    public static function on_auto_update($results) {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('auto_update_installed')) {
            return;
        }

        $update_types = array('core', 'plugin', 'theme', 'translation');
        foreach ($update_types as $type) {
            if (empty($results[$type])) {
                continue;
            }
            foreach ($results[$type] as $item) {
                // Skip failed updates — only alert on successful installs
                if (isset($item->result) && ($item->result === false || is_wp_error($item->result))) {
                    continue;
                }

                $name = '';
                $old_version = '';
                $new_version = '';

                if ($type === 'core' && is_object($item)) {
                    $name = 'WordPress Core';
                    $new_version = isset($item->current) ? $item->current : '';
                } elseif (is_object($item) && isset($item->item)) {
                    $item_data = $item->item;
                    if ($type === 'plugin' && is_object($item_data)) {
                        $name = isset($item_data->slug) ? $item_data->slug : '';
                        $new_version = isset($item_data->new_version) ? $item_data->new_version : '';
                    } elseif ($type === 'theme' && is_array($item_data)) {
                        $name = isset($item_data['theme']) ? $item_data['theme'] : '';
                        $new_version = isset($item_data['new_version']) ? $item_data['new_version'] : '';
                    }
                }

                $context = array(
                    'component_name' => $name ? $name : ucfirst($type),
                    'update_type'    => ucfirst($type),
                    'old_version'    => $old_version,
                    'new_version'    => $new_version,
                    'updated_at'     => current_time('Y-m-d H:i:s'),
                );

                VMPFence_Email_Service::send_alert('auto_update_installed', $context);
            }
        }
    }

    // =====================================================================
    // ACCOUNT LOCKOUT ALERT
    // =====================================================================

    /**
     * Fires on vmpfence_brute_force_lockout.
     *
     * @since 2.2.6
     * @param string $ip              The locked-out IP.
     * @param int    $duration         Lockout duration in seconds.
     * @param bool   $permanent        Whether the ban is permanent.
     * @param int    $failed_attempts  Number of failed attempts.
     */
    public static function on_account_lockout($ip, $duration, $permanent, $failed_attempts) {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('account_lockout')) {
            return;
        }

        $duration_minutes = $permanent ? 'Permanent' : round($duration / 60);

        $context = array(
            'locked_username'         => '', // IP-based lockout; username not always known
            'failed_attempts'         => $failed_attempts,
            'lockout_duration_minutes' => $duration_minutes,
            'source_ip'               => $ip,
            'country'                 => self::get_ip_country($ip),
            'locked_at'               => current_time('Y-m-d H:i:s'),
        );

        VMPFence_Email_Service::send_alert('account_lockout', $context);
    }

    // =====================================================================
    // IP BLOCKED ALERT
    // =====================================================================

    /**
     * Fires on vmpfence_ip_blocked.
     *
     * @since 2.2.6
     * @param string $ip_address  The blocked IP.
     * @param string $reason      Reason for blocking.
     * @param string $block_type  Type of block (e.g., 'manual', 'brute_force', 'waf').
     */
    public static function on_ip_blocked($ip_address, $reason = '', $block_type = '') {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('ip_blocked')) {
            return;
        }

        $context = array(
            'blocked_ip'    => $ip_address,
            'reason'        => $reason,
            'rule_matched'  => $block_type,
            'country'       => self::get_ip_country($ip_address),
            'blocked_at'    => current_time('Y-m-d H:i:s'),
            'block_duration' => '', // Not available from the hook; could be added later
        );

        VMPFence_Email_Service::send_alert('ip_blocked', $context);
    }

    // =====================================================================
    // WAF DISABLED ALERT
    // =====================================================================

    /**
     * Fires on vmpfence_config_changed. Checks if WAF was disabled.
     *
     * @since 2.2.6
     * @param string $key        Config key that changed.
     * @param mixed  $old_value  Previous value.
     * @param mixed  $new_value  New value.
     */
    public static function on_config_changed($key, $old_value, $new_value) {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }

        // WAF disabled detection
        if ($key === 'waf_enabled' && !self::is_truthy($new_value) && self::is_truthy($old_value)) {
            if (!VMPFence_Email_Service::is_alert_enabled('waf_disabled')) {
                return;
            }

            $current_user = wp_get_current_user();
            $context = array(
                'disabled_by'  => ($current_user && $current_user->ID) ? $current_user->user_login : 'Unknown',
                'disabled_at'  => current_time('Y-m-d H:i:s'),
                'reason'       => '',
                'settings_url' => admin_url('admin.php?page=vmpfence-firewall'),
            );

            VMPFence_Email_Service::send_alert('waf_disabled', $context);
        }
    }

    // =====================================================================
    // PLUGIN DEACTIVATED ALERT
    // =====================================================================

    /**
     * Fires on plugin deactivation. Called synchronously before PHP shuts down.
     *
     * @since 2.2.6
     */
    public static function on_plugin_deactivated() {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('plugin_deactivated')) {
            return;
        }

        $current_user = wp_get_current_user();
        $context = array(
            'deactivated_by'  => ($current_user && $current_user->ID) ? $current_user->user_login : 'Unknown',
            'deactivated_at'  => current_time('Y-m-d H:i:s'),
            'reactivation_url' => admin_url('plugins.php'),
        );

        VMPFence_Email_Service::send_alert('plugin_deactivated', $context);
    }

    // =====================================================================
    // BREACHED PASSWORD ALERT (called externally)
    // =====================================================================

    /**
     * Send a breached password alert. Called from wherever breached password
     * detection happens (e.g., login check, password change check).
     *
     * @since 2.2.6
     * @param int    $user_id          The user ID.
     * @param string $detection_method How it was detected (e.g., 'Have I Been Pwned API').
     */
    public static function send_breached_password_alert($user_id, $detection_method = '') {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('breached_password')) {
            return;
        }

        $user = get_userdata($user_id);
        if (!$user) {
            return;
        }

        $context = array(
            'username'         => $user->user_login,
            'user_email'       => $user->user_email,
            'user_role'        => !empty($user->roles) ? ucfirst($user->roles[0]) : 'Subscriber',
            'detection_method' => $detection_method ? $detection_method : 'Password breach database check',
            'edit_user_url'    => admin_url('user-edit.php?user_id=' . $user->ID),
        );

        VMPFence_Email_Service::send_alert('breached_password', $context);
    }

    // =====================================================================
    // ATTACK SPIKE ALERT (called externally)
    // =====================================================================

    /**
     * Send an attack spike alert. Called from rate monitoring code.
     *
     * @since 2.2.6
     * @param int   $current_rate        Current attacks per hour.
     * @param int   $normal_rate         Normal/baseline attacks per hour.
     * @param int   $increase_percentage Percentage increase.
     * @param array $top_attacking_ips   Array of {ip, count} entries.
     * @param array $attack_types        List of attack type labels.
     * @param string $period             Time period description (e.g., 'Last 1 hour').
     */
    public static function send_attack_spike_alert($current_rate, $normal_rate, $increase_percentage, $top_attacking_ips = array(), $attack_types = array(), $period = '') {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        if (!VMPFence_Email_Service::is_alert_enabled('attack_spike')) {
            return;
        }

        $context = array(
            'current_rate'        => $current_rate,
            'normal_rate'         => $normal_rate,
            'increase_percentage' => $increase_percentage,
            'top_attacking_ips'   => $top_attacking_ips,
            'attack_types'        => $attack_types,
            'period'              => $period ? $period : 'Last 1 hour',
            'dashboard_url'       => admin_url('admin.php?page=vmpfence-firewall'),
        );

        VMPFence_Email_Service::send_alert('attack_spike', $context);
    }

    // =====================================================================
    // GSB BLOCKLIST DETECTED (called externally from scan scheduler)
    // =====================================================================

    /**
     * Send a GSB blocklist detection alert. Called from executeDomainBlocklistScanner
     * when issues_found > 0.
     *
     * This alert bypasses rate limits and the scan_severity threshold because
     * being on the GSB blocklist is always critical.
     *
     * @since 2.2.6
     * @param string $domain        The flagged domain.
     * @param array  $threat_types  List of threat type labels.
     * @param string $detected_at   Timestamp of detection.
     */
    public static function send_gsb_blocklist_alert($domain, $threat_types = array(), $detected_at = '') {
        if (!class_exists('VMPFence_Email_Service')) {
            return;
        }
        // GSB toggle is scansEnabled_checkGSB — if GSB scanning is enabled,
        // the alert should fire. No separate toggle for the alert.
        if (!VMPFence_Email_Service::is_alert_enabled('gsb_blocklist_detected')) {
            return;
        }

        $context = array(
            'domain'           => $domain,
            'threat_types'     => $threat_types,
            'blocklist_source' => 'Google Safe Browsing',
            'detected_at'      => $detected_at ? $detected_at : current_time('Y-m-d H:i:s'),
            'dashboard_url'    => admin_url('admin.php?page=vmpfence-scan'),
        );

        VMPFence_Email_Service::send_alert('gsb_blocklist_detected', $context);
    }

    // =====================================================================
    // HELPER METHODS
    // =====================================================================

    /**
     * Get the client IP address using VMPFence's IP detection if available.
     *
     * @since 2.2.6
     * @return string
     */
    private static function get_client_ip() {
        if (class_exists('VMPFence_Utils') && method_exists('VMPFence_Utils', 'get_real_ip')) {
            return VMPFence_Utils::get_real_ip();
        }
        // Fallback: REMOTE_ADDR only (safe — no header trust without config)
        return isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
    }

    /**
     * Get the country for an IP using GeoIP if available.
     *
     * @since 2.2.6
     * @param string $ip
     * @return string  Country name or empty string.
     */
    private static function get_ip_country($ip) {
        // Use VMPFence's GeoIP integration if available
        if (class_exists('VMPFence_Utils') && method_exists('VMPFence_Utils', 'geolocate_ip')) {
            $geo = VMPFence_Utils::geolocate_ip($ip);
            return !empty($geo['country_name']) ? $geo['country_name'] : '';
        }
        return '';
    }

    /**
     * Check if a login IP is new for the given user (MVP: IP-based detection).
     *
     * Uses a user meta key to store known login IPs (up to 50).
     *
     * @since 2.2.6
     * @param int    $user_id
     * @param string $ip
     * @return bool  True if this IP has not been seen for this user.
     */
    private static function is_new_device_ip($user_id, $ip) {
        if (empty($ip)) {
            return false;
        }
        $known_ips = get_user_meta($user_id, '_vmpfence_known_login_ips', true);
        if (!is_array($known_ips)) {
            $known_ips = array();
        }
        return !in_array($ip, $known_ips, true);
    }

    /**
     * Record a login IP for future new-device detection.
     *
     * @since 2.2.6
     * @param int    $user_id
     * @param string $ip
     */
    private static function record_login_ip($user_id, $ip) {
        if (empty($ip)) {
            return;
        }
        $known_ips = get_user_meta($user_id, '_vmpfence_known_login_ips', true);
        if (!is_array($known_ips)) {
            $known_ips = array();
        }
        if (!in_array($ip, $known_ips, true)) {
            $known_ips[] = $ip;
            // Cap at 50 IPs per user to avoid bloat
            if (count($known_ips) > 50) {
                $known_ips = array_slice($known_ips, -50);
            }
            update_user_meta($user_id, '_vmpfence_known_login_ips', $known_ips);
        }
    }

    /**
     * Get a simple device summary from the user agent string.
     *
     * @since 2.2.6
     * @param string $user_agent
     * @return string
     */
    private static function get_device_summary($user_agent) {
        if (empty($user_agent)) {
            return 'Unknown device';
        }

        $device = 'Unknown';
        if (strpos($user_agent, 'Mobile') !== false || strpos($user_agent, 'Android') !== false) {
            $device = 'Mobile';
        } elseif (strpos($user_agent, 'Tablet') !== false || strpos($user_agent, 'iPad') !== false) {
            $device = 'Tablet';
        } else {
            $device = 'Desktop';
        }

        $browser = 'Unknown browser';
        if (strpos($user_agent, 'Firefox') !== false) {
            $browser = 'Firefox';
        } elseif (strpos($user_agent, 'Edg/') !== false) {
            $browser = 'Edge';
        } elseif (strpos($user_agent, 'Chrome') !== false) {
            $browser = 'Chrome';
        } elseif (strpos($user_agent, 'Safari') !== false) {
            $browser = 'Safari';
        }

        return $device . ' / ' . $browser;
    }

    /**
     * Check if a config value is truthy (handles strings '1', 'true', etc.)
     *
     * @since 2.2.6
     * @param mixed $value
     * @return bool
     */
    private static function is_truthy($value) {
        if (is_bool($value)) {
            return $value;
        }
        if (is_string($value)) {
            return in_array(strtolower($value), array('1', 'true', 'yes', 'on'), true);
        }
        return (bool) $value;
    }
}