<?php
/**
 * WAF Log Model
 *
 * @package VMPFence
 * @since 2.0.0
 */

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

/**
 * WAF Log Model Class
 *
 * @since 2.0.0
 */
class VMPFence_WAF_Log {

    /**
     * Log attack
     *
     * @since 2.0.0
     * @param array $attack_data Attack data
     * @return int|false Log ID or false on failure
     */
    public static function log_attack($attack_data) {
        global $wpdb;
        $table_name = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_WAF_LOG);

        $defaults = array(
            'attackLogTime' => microtime(true),
            'IP' => isset($_SERVER['REMOTE_ADDR']) ? inet_pton($_SERVER['REMOTE_ADDR']) : '',
            'countryCode' => null,
            'severity' => 0,
            'action' => 'block',
            'actionDescription' => '',
            'actionData' => '',
            'logMsg' => '',
            'request_uri' => isset($_SERVER['REQUEST_URI']) ? sanitize_text_field($_SERVER['REQUEST_URI']) : '',
            'http_referer' => isset($_SERVER['HTTP_REFERER']) ? sanitize_text_field($_SERVER['HTTP_REFERER']) : '',
            'http_user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field($_SERVER['HTTP_USER_AGENT']) : '',
        );

        $attack_data = wp_parse_args($attack_data, $defaults);

        $result = $wpdb->insert(
            $table_name,
            array(
                'attackLogTime' => $attack_data['attackLogTime'],
                'IP' => $attack_data['IP'],
                'countryCode' => $attack_data['countryCode'],
                'severity' => $attack_data['severity'],
                'action' => $attack_data['action'],
                'actionDescription' => $attack_data['actionDescription'],
                'actionData' => $attack_data['actionData'],
                'logMsg' => $attack_data['logMsg'],
                'request_uri' => $attack_data['request_uri'],
                'http_referer' => $attack_data['http_referer'],
                'http_user_agent' => $attack_data['http_user_agent'],
            ),
            array('%f', '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s')
        );

        return $result ? $wpdb->insert_id : false;
    }

    /**
     * Log violation details
     *
     * @since 2.0.0
     * @param array $violations Array of violated rule IDs and matched values
     * @param int $total_score Total score
     * @param string $action Action taken (block, log)
     * @return int|false Log ID or false on failure
     */
    public static function log_violation_details($violations, $total_score, $action = 'block') {
        $action_data = wp_json_encode(array(
            'violations' => $violations,
            'total_score' => $total_score,
            'timestamp' => time(),
        ));

        return self::log_attack(array(
            'severity' => self::calculate_severity($total_score),
            'action' => $action,
            'actionDescription' => 'WAF rule violation',
            'actionData' => $action_data,
            'logMsg' => sprintf('WAF detected %d violations with score %d', count($violations), $total_score),
        ));
    }

    /**
     * Get recent attacks
     *
     * @since 2.0.0
     * @param int $limit Number of attacks to retrieve
     * @param int $offset Offset for pagination
     * @return array
     */
    public static function get_recent_attacks($limit = 50, $offset = 0) {
        global $wpdb;
        $table_name = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_WAF_LOG);

        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM $table_name ORDER BY attackLogTime DESC LIMIT %d OFFSET %d",
                $limit,
                $offset
            ),
            ARRAY_A
        );
    }

    /**
     * Get statistics by severity
     *
     * @since 2.0.0
     * @param int $days Number of days to include (default: 30)
     * @return array
     */
    public static function get_stats_by_severity($days = 30) {
        global $wpdb;
        $table_name = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_WAF_LOG);

        $cutoff_time = microtime(true) - ($days * 24 * 60 * 60);

        $stats = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT severity, COUNT(*) as count 
                FROM $table_name 
                WHERE attackLogTime > %f 
                GROUP BY severity 
                ORDER BY severity DESC",
                $cutoff_time
            ),
            ARRAY_A
        );

        return $stats;
    }

    /**
     * Calculate severity based on score
     *
     * @since 2.0.0
     * @param int $score Total violation score
     * @return int Severity level (0-5)
     */
    private static function calculate_severity($score) {
        if ($score >= 200) {
            return 5; // Critical
        } elseif ($score >= 150) {
            return 4; // High
        } elseif ($score >= 100) {
            return 3; // Medium
        } elseif ($score >= 50) {
            return 2; // Low
        } elseif ($score > 0) {
            return 1; // Info
        }
        return 0; // None
    }

    /**
     * Get attacks by category
     *
     * @since 2.0.0
     * @param int $days Number of days
     * @return array
     */
    public static function get_stats_by_category($days = 30) {
        global $wpdb;
        $table_name = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_WAF_LOG);

        $cutoff_time = microtime(true) - ($days * 24 * 60 * 60);

        $stats = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT actionData, COUNT(*) as count 
                FROM $table_name 
                WHERE attackLogTime > %f AND action = 'block'
                GROUP BY actionData",
                $cutoff_time
            ),
            ARRAY_A
        );

        $category_stats = array();
        foreach ($stats as $stat) {
            $data = json_decode($stat['actionData'], true);
            if (isset($data['violations']) && is_array($data['violations'])) {
                foreach ($data['violations'] as $violation) {
                    if (isset($violation['category'])) {
                        $category = $violation['category'];
                        if (!isset($category_stats[$category])) {
                            $category_stats[$category] = 0;
                        }
                        $category_stats[$category]++;
                    }
                }
            }
        }

        return $category_stats;
    }

    /**
     * Get total attacks count
     *
     * @since 2.0.0
     * @param int $days Number of days
     * @return int
     */
    public static function get_total_attacks($days = 30) {
        global $wpdb;
        $table_name = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_WAF_LOG);

        $cutoff_time = microtime(true) - ($days * 24 * 60 * 60);

        $count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM $table_name WHERE attackLogTime > %f",
                $cutoff_time
            )
        );

        return intval($count);
    }

    /**
     * Get top blocked IPs by period
     * 
     * Shows IPs that are currently blocked (banned from the site),
     * NOT individual WAF attack blocks. Filters by when the IP was first blocked.
     * 
     * @since 2.1.0
     * @param string $period '24h', '7d', or '30d'
     * @param int $limit Number of IPs to return (default: 10)
     * @return array Array of top blocked IPs with counts
     */
    public static function get_top_blocked_ips($period = '24h', $limit = 10) {
        global $wpdb;
        $blocked_ips_table = VMPFence_Constants::get_table_name(VMPFence_Constants::TABLE_BLOCKED_IPS);
        
        // Calculate timestamp threshold based on period
        $time_thresholds = array(
            '24h' => 60 * 60 * 24,
            '7d' => 60 * 60 * 24 * 7,
            '30d' => 60 * 60 * 24 * 30
        );
        
        $seconds = isset($time_thresholds[$period]) 
            ? $time_thresholds[$period]
            : $time_thresholds['24h'];
        
        $threshold = time() - $seconds;
        
        // Validate and sanitize limit
        $limit = absint($limit);
        if ($limit < 1 || $limit > 100) {
            $limit = 10;
        }
        
        // Query blocked IPs table - count total records per IP address
        // Since we insert new records for each block, COUNT(*) gives us the total blocks
        $sql = $wpdb->prepare(
            "SELECT 
                ip_address,
                COUNT(*) as block_count,
                NULL as countryCode,
                MAX(blocked_at) as last_block
            FROM {$blocked_ips_table}
            WHERE source = 'local'
                AND blocked_at >= %d
            GROUP BY ip_address
            ORDER BY block_count DESC
            LIMIT %d",
            $threshold,
            $limit
        );
        
        $results = $wpdb->get_results($sql, ARRAY_A);
        
        return $results ? $results : array();
    }
}
