<?php
/**
 * Guardify Firewall Class
 */
class Guardify_Firewall {
    private $settings;
    private $geo;

    public function __construct() {
        $this->settings = get_option('guardify_settings', $this->default_settings());
        $this->geo = new SG_guardify_Geo_IP2Country();
        add_action('init', [$this, 'protect']);
        add_action('wp_login', [$this, 'log_login'], 10, 2);
        add_action('wp_login_failed', [$this, 'log_failed_login']);
        // Hooks for WordPress Security
        add_action('admin_init', [$this, 'block_plugin_theme_install']);
        add_action('admin_init', [$this, 'block_theme_editor']);
        add_filter('pre_comment_approved', [$this, 'filter_comment_content'], 10, 3);
    }

    private function default_settings() {
        return [
            'enabled' => 0,
            'block_bruteforce' => 1,
            'notify_login_country_change' => 1,
            'advanced_bot_control' => 0,
            'enable_2fa' => 0,
            'rate_limit' => 1000, // Requests/hour
            'blocked_user_agents' => 'bot,scanner,crawler',
            'geo_block_countries' => '',
            'block_plugin_theme_install' => 0,
            'block_theme_editor' => 0,
            'forbidden_comment_words' => 'http,https,www,viagra,casino,porn',
            'auto_block_ip_htaccess' => 0,
        ];
    }

    public function protect() {
        if (!$this->settings['enabled'] || is_admin()) return;

        // Validate $_SERVER['REMOTE_ADDR']
        $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
        if (empty($ip)) {
            return; // If IP is not available, exit early
        }

        $this->log_activity($ip);

        // Check IP rules
        $ip_rules = get_option('guardify_ip_rules', []);
        $is_allowed = false;
        $is_blocked = false;

        foreach ($ip_rules as $rule) {
            if ($this->is_ip_expired($rule)) continue;

            if ($this->ip_in_range($ip, $rule['ip'])) {
                if ($rule['type'] === 'allow') {
                    $is_allowed = true;
                    break; // Allow rules take precedence
                } elseif ($rule['type'] === 'block') {
                    $is_blocked = true;
                }
            }
        }

        if ($is_blocked && !$is_allowed) {
            $this->block_request('Blacklisted IP');
        }

        if (!$is_allowed) {
            if ($this->is_suspicious_request()) $this->block_request('Suspicious URL');
            if ($this->is_sql_injection()) $this->block_request('SQL Injection');
            if ($this->is_xss_attack()) $this->block_request('XSS Attack');
            if ($this->is_rate_limited($ip)) {
                $this->block_request('Rate Limit Exceeded');
                if ($this->settings['auto_block_ip_htaccess']) {
                    $this->add_ip_to_htaccess($ip);
                }
            }
            if ($this->is_blocked_user_agent()) $this->block_request('Blocked User-Agent');
        }

        if ($this->settings['geo_block_countries']) {
            $country = $this->get_country($ip);
            if (in_array($country, explode(',', $this->settings['geo_block_countries']))) {
                $this->block_request('Geo-Blocked Country');
            }
        }
    }

    // Block plugin and theme installation
    public function block_plugin_theme_install() {
        if (!$this->settings['block_plugin_theme_install']) return;

        if (current_user_can('install_plugins') || current_user.can('install_themes')) {
            $current_page = basename($_SERVER['PHP_SELF']);
            if (in_array($current_page, ['plugin-install.php', 'theme-install.php'])) {
                wp_die(
                    sprintf(
                        /* translators: %s: Reason for access denial */
                        esc_html__('Installation of plugins and themes has been disabled by Guardify: %s', 'guardify'),
                        esc_html__('Access Denied', 'guardify')
                    ),
                    esc_html__('Access Denied', 'guardify'),
                    ['response' => 403]
                );
            }
        }
    }

    // Block theme editor
    public function block_theme_editor() {
        if (!$this->settings['block_theme_editor']) return;

        $current_page = basename($_SERVER['PHP_SELF']);
        if ($current_page === 'theme-editor.php') {
            wp_die(
                sprintf(
                    /* translators: %s: Reason for access denial */
                    esc_html__('Theme editor access has been disabled by Guardify: %s', 'guardify'),
                    esc_html__('Access Denied', 'guardify')
                ),
                esc_html__('Access Denied', 'guardify'),
                ['response' => 403]
            );
        }
    }

    // Filter comments for forbidden words
    public function filter_comment_content($approved, $commentdata, $comment_id) {
        if (empty($this->settings['forbidden_comment_words'])) return $approved;

        $forbidden_words = array_map('trim', explode(',', $this->settings['forbidden_comment_words']));
        $comment_content = strtolower($commentdata['comment_content']);

        foreach ($forbidden_words as $word) {
            if (empty($word)) continue;
            if (stripos($comment_content, $word) !== false) {
                $this->log_block('Forbidden word in comment: ' . $word);
                return 'spam'; // Mark comment as spam
            }
        }

        return $approved;
    }

    public static function setup_ini() {
        $file = GUARDIFY_PATH . 'firewall.php';
        if (file_exists('.user.ini')) {
            file_put_contents('.user.ini', "auto_prepend_file = $file\n", FILE_APPEND);
        }
    }

    public static function remove_ini() {}

    private function is_suspicious_request() {
        $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
        return preg_match('/(wp-content|wp-includes|themes|plugins).*\.php|(\.\.\/|<script>)/i', $uri);
    }

    private function is_sql_injection() {
        $request = array_merge($_GET, $_POST);
        foreach ($request as $value) {
            $value = sanitize_text_field(wp_unslash($value));
            if (preg_match('/(union|select|insert|drop|delete|--|\/\*)/i', $value)) return true;
        }
        return false;
    }

    private function is_xss_attack() {
        $request = array_merge($_GET, $_POST);
        foreach ($request as $value) {
            $value = sanitize_text_field(wp_unslash($value));
            if (preg_match('/(<script|onerror|onload|javascript:)/i', $value)) return true;
        }
        return false;
    }

    private function is_rate_limited($ip) {
        $cache_key = 'guardify_rate_' . md5($ip);
        $requests = (int) get_transient($cache_key);
        if ($requests >= $this->settings['rate_limit']) return true;
        set_transient($cache_key, $requests + 1, HOUR_IN_SECONDS); // Changed to hour
        return false;
    }

    private function is_blocked_user_agent() {
        $ua = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
        $blocked = array_map('trim', explode(',', $this->settings['blocked_user_agents']));
        foreach ($blocked as $agent) {
            if (stripos($ua, $agent) !== false) return true;
        }
        return false;
    }

    private function block_request($reason) {
        $this->log_block($reason);
        wp_die(
            sprintf(
                /* translators: %s: Reason for access denial */
                esc_html__('Access Denied by Guardify Firewall: %s', 'guardify'),
                esc_html($reason)
            ),
            esc_html__('Access Denied', 'guardify'),
            ['response' => 403]
        );
    }

    private function log_activity($ip) {
        $log = [
            'ip' => $ip,
            'time' => current_time('mysql'),
            'uri' => isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '',
            'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '',
            'country' => $this->get_country($ip),
        ];
        file_put_contents(GUARDIFY_LOG_DIR . '/activity.log', json_encode($log) . "\n", FILE_APPEND);
    }

    private function log_block($reason) {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
        $log = [
            'ip' => $ip,
            'time' => current_time('mysql'),
            'reason' => $reason,
            'country' => $this->get_country($ip),
        ];
        file_put_contents(GUARDIFY_LOG_DIR . '/blocks.log', json_encode($log) . "\n", FILE_APPEND);
    }

    public function log_login($user_login, $user) {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
        $last_country = get_user_meta($user->ID, 'guardify_last_country', true);
        $current_country = $this->get_country($ip);

        $log = [
            'user' => $user_login,
            'ip' => $ip,
            'time' => current_time('mysql'),
            'country' => $current_country,
            'status' => 'success',
        ];
        file_put_contents(GUARDIFY_LOG_DIR . '/logins.log', json_encode($log) . "\n", FILE_APPEND);

        if ($this->settings['notify_login_country_change'] && $last_country && $last_country !== $current_country) {
            wp_mail(
                $user->user_email,
                esc_html__('Login Country Changed', 'guardify'),
                sprintf(
                    /* translators: %1$s: Current country, %2$s: Previous country */
                    esc_html__('Login detected from %1$s (previously %2$s).', 'guardify'),
                    $this->geo->getNameByCountryCode($current_country),
                    $this->geo->getNameByCountryCode($last_country)
                )
            );
        }
        update_user_meta($user->ID, 'guardify_last_country', $current_country);
    }

    public function log_failed_login($username) {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
        $log = [
            'user' => sanitize_text_field($username),
            'ip' => $ip,
            'time' => current_time('mysql'),
            'country' => $this->get_country($ip),
            'status' => 'failed',
        ];
        file_put_contents(GUARDIFY_LOG_DIR . '/logins.log', json_encode($log) . "\n", FILE_APPEND);
    }

    private function get_country($ip) {
        $country_code = $this->geo->getCountryByIP($ip);
        return $country_code ?: 'Unknown';
    }

    private function ip_in_range($ip, $range) {
        if (empty($range)) return false;

        if (strpos($range, '/') !== false) {
            list($subnet, $mask) = explode('/', $range);
            return $this->ip_in_subnet($ip, $subnet, $mask);
        } else {
            return $ip === $range;
        }
    }

    private function ip_in_subnet($ip, $subnet, $mask) {
        $ip_long = ip2long($ip);
        $subnet_long = ip2long($subnet);
        if ($ip_long === false || $subnet_long === false) return false;

        $mask = ~((1 << (32 - $mask)) - 1);
        return ($ip_long & $mask) === ($subnet_long & $mask);
    }

    private function is_ip_expired($rule) {
        if (empty($rule['expiry'])) return false;
        $expiry = strtotime($rule['expiry']);
        $now = current_time('timestamp');
        return $now > $expiry;
    }

    // Add IP to .htaccess for permanent blocking
    private function add_ip_to_htaccess($ip) {
        $htaccess_file = ABSPATH . '.htaccess';
        
        // Use WP_Filesystem to check if the file is writable
        if (!function_exists('WP_Filesystem')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        global $wp_filesystem;
        if (!WP_Filesystem()) {
            return; // Cannot initialize WP_Filesystem
        }

        if (!$wp_filesystem->is_writable($htaccess_file)) {
            return; // Cannot write to .htaccess
        }

        $marker_start = "# BEGIN Guardify IP Block\n";
        $marker_end = "# END Guardify IP Block\n";
        $new_rule = "Deny from $ip\n";

        $htaccess_content = $wp_filesystem->get_contents($htaccess_file);
        if (strpos($htaccess_content, $marker_start) === false) {
            // Add new block
            $new_content = $marker_start . $new_rule . $marker_end;
            $wp_filesystem->put_contents($htaccess_file, $htaccess_content . "\n" . $new_content);
        } else {
            // Update existing block
            $start_pos = strpos($htaccess_content, $marker_start);
            $end_pos = strpos($htaccess_content, $marker_end, $start_pos);
            $existing_block = substr($htaccess_content, $start_pos, $end_pos - $start_pos);
            if (strpos($existing_block, $ip) === false) {
                $new_block = $existing_block . $new_rule;
                $htaccess_content = str_replace($existing_block, $new_block, $htaccess_content);
                $wp_filesystem->put_contents($htaccess_file, $htaccess_content);
            }
        }
    }
}