<?php
/**
 * VMPFence Scan Statistics Collector
 * 
 * Centralized system for collecting comprehensive scan statistics
 * 
 *
 * @package VMPFence
 * @since 1.0.0
 */

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

class VMPFence_Scan_Statistics_Collector {
    
    /**
     * Scan statistics data
     * @var array
     */
    private $statistics = array();
    
    /**
     * Scan start time
     * @var float
     */
    private $scan_start_time;
    
    /**
     * Scan end time
     * @var float
     */
    private $scan_end_time;
    
    /**
     * Current scan ID
     * @var string
     */
    private $scan_id;
    
    /**
     * Singleton instance
     * @var VMPFence_Scan_Statistics_Collector
     */
    private static $instance = null;
    
    /**
     * Get singleton instance
     */
    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Constructor
     */
    private function __construct() {
        $this->initialize_statistics();
    }
    
    /**
     * Initialize statistics array
     */
    private function initialize_statistics() {
        $this->statistics = array(
            'files_scanned' => 0,
            'plugins_scanned' => 0,
            'themes_scanned' => 0,
            'posts_scanned' => 0,
            'comments_scanned' => 0,
            'urls_scanned' => 0,
            'users_scanned' => 0,
            'scan_duration' => 0,
            'scan_type' => 'Standard Scan',
            'started_time' => null,
            'completed_time' => null
        );
    }
    
    /**
     * Start scan statistics collection
     */
    public function start_scan($scan_type = 'Standard Scan') {
        $this->scan_start_time = microtime(true);
        $this->scan_id = uniqid('vmpfence_scan_');
        $this->statistics['scan_type'] = $scan_type;
        $this->statistics['started_time'] = current_time('mysql');
        
        // Reset all counters
        $this->initialize_statistics();
        $this->statistics['scan_type'] = $scan_type;
        $this->statistics['started_time'] = current_time('mysql');
    }
    
    /**
     * End scan statistics collection
     */
    public function end_scan() {
        $this->scan_end_time = microtime(true);
        $this->statistics['completed_time'] = current_time('mysql');
        $this->statistics['scan_duration'] = round($this->scan_end_time - $this->scan_start_time);
        
        // Save to database
        $this->save_statistics();
        
        return $this->statistics;
    }
    
    /**
     * Add files scanned count
     */
    public function add_files_scanned($count) {
        $this->statistics['files_scanned'] += (int)$count;
    }
    
    /**
     * Set plugins scanned count
     */
    public function set_plugins_scanned($count) {
        $this->statistics['plugins_scanned'] = (int)$count;
    }
    
    /**
     * Set themes scanned count
     */
    public function set_themes_scanned($count) {
        $this->statistics['themes_scanned'] = (int)$count;
    }
    
    /**
     * Set posts scanned count
     */
    public function set_posts_scanned($count) {
        $this->statistics['posts_scanned'] = (int)$count;
    }
    
    /**
     * Set comments scanned count
     */
    public function set_comments_scanned($count) {
        $this->statistics['comments_scanned'] = (int)$count;
    }
    
    /**
     * Set URLs scanned count
     */
    public function set_urls_scanned($count) {
        $this->statistics['urls_scanned'] = (int)$count;
    }
    
    /**
     * Set users scanned count
     */
    public function set_users_scanned($count) {
        $this->statistics['users_scanned'] = (int)$count;
    }
    
    /**
     * Get current statistics
     */
    public function get_statistics() {
        return $this->statistics;
    }
    
    /**
     * Hoover URLs from content
     * Uses regex to find all URLs in text content and returns count
     */
    private function hoover_urls_from_content($content) {
        $found_count = 0;
        
        // Matches: //domain.com/path or http://domain.com/path or https://domain.com/path
        $pattern = '_((?:(?://)(?:\S+(?::\S*)?@)?(?:(?:(?:[a-z\xa1-\xff0-9.-]+)(?:\.(?:(?:xn--[a-z\xa1-\xff0-9-]+)|[a-z\xa1-\xff]{2,}))))(?::\d{2,5})?)(?:/[a-z0-9\-\_\.~\!\*\(\);\:@&\=\+\$,\?#\[\]%]*)*)_iS';
        
        if (preg_match_all($pattern, $content, $matches)) {
            foreach ($matches[0] as $url_match) {
                $url = (strpos($url_match, 'http') === 0) ? $url_match : 'http:' . $url_match;
                
                // Validate URL
                if (filter_var($url, FILTER_VALIDATE_URL)) {
                    $components = wp_parse_url($url);
                    
                    // Check for valid TLD (simplified version)
                    if (isset($components['host']) && preg_match('/\.[a-z]{2,}$/i', $components['host'])) {
                        $found_count++;
                    }
                }
            }
        }
        
        return $found_count;
    }
    
    /**
     * Get WordPress counts automatically - count what will actually be scanned
     */
    public function collect_wordpress_counts() {
        global $wpdb;
        
        // Count ALL plugins
        if (!function_exists('get_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        $all_plugins = get_plugins(); // Get all plugins (active + inactive + premium/custom + single-file)
        $active_plugins = get_option('active_plugins', array());
        
        // Count ALL plugins including single-file ones like hello.php
        $plugin_count = count($all_plugins);
        $this->set_plugins_scanned($plugin_count);
        
        // Count ALL themes (what VMPFence actually scans - both active and inactive)
        $all_themes = wp_get_themes(); // Get all installed themes
        $active_theme = wp_get_theme();
        $theme_count = count($all_themes);
        $this->set_themes_scanned($theme_count);
        
        $theme_names = array();
        foreach ($all_themes as $theme_slug => $theme_obj) {
            $status = ($theme_slug === get_stylesheet()) ? 'active' : 'inactive';
            $theme_names[] = $theme_obj->get('Name') . " ({$status})";
        }
        
        // Count published posts
        $post_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ('post', 'page')");
        $this->set_posts_scanned((int)$post_count);
        
        // Count approved comments
        $comment_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_approved = '1'");
        $this->set_comments_scanned((int)$comment_count);
        
        // Count users
        $user_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->users}");
        $this->set_users_scanned((int)$user_count);
        
        // Comprehensive URL counting
        $total_urls = 0;
        
        // 1. All published posts and pages URLs
        $post_urls = (int)$post_count;
        $total_urls += $post_urls;
        
        // 2. Media attachment URLs
        $attachment_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'attachment'");
        $total_urls += (int)$attachment_count;
        
        // 3. URLs found in post content (hoover extraction)
        $posts_with_content = $wpdb->get_results("
            SELECT post_title, post_content, post_excerpt FROM {$wpdb->posts} 
            WHERE post_status = 'publish'
        ");
        
        $extracted_urls = 0;
        foreach ($posts_with_content as $post) {
            $content_data = $post->post_title . ' ' . $post->post_content . ' ' . $post->post_excerpt;
            $found_urls = $this->hoover_urls_from_content($content_data);
            $extracted_urls += $found_urls;
        }
        $total_urls += $extracted_urls;
        
        // 4. URLs in comments (hoover extraction)
        $comments_with_content = $wpdb->get_results("
            SELECT comment_author_url, comment_author, comment_content FROM {$wpdb->comments} 
            WHERE comment_approved = '1'
        ");
        
        $comment_extracted_urls = 0;
        foreach ($comments_with_content as $comment) {
            $content_data = $comment->comment_author_url . ' ' . $comment->comment_author . ' ' . $comment->comment_content;
            $found_urls = $this->hoover_urls_from_content($content_data);
            $comment_extracted_urls += $found_urls;
        }
        $total_urls += $comment_extracted_urls;
        
        // 5. URLs in WordPress options
        $options_with_content = $wpdb->get_results("
            SELECT option_name, option_value FROM {$wpdb->options}
            WHERE option_value LIKE '%http%'
        ");
        
        $option_extracted_urls = 0;
        foreach ($options_with_content as $option) {
            $found_urls = $this->hoover_urls_from_content($option->option_value);
            $option_extracted_urls += $found_urls;
        }
        $total_urls += $option_extracted_urls;
        
        // 6. Custom post types URLs
        $custom_post_types = get_post_types(['public' => true, '_builtin' => false]);
        foreach ($custom_post_types as $post_type) {
            $cpt_count = $wpdb->get_var($wpdb->prepare("
                SELECT COUNT(*) FROM {$wpdb->posts} 
                WHERE post_type = %s AND post_status = 'publish'
            ", $post_type));
            $total_urls += (int)$cpt_count;
        }
        
        // 7. Menu items URLs
        $menu_urls = $wpdb->get_var("
            SELECT COUNT(*) FROM {$wpdb->posts} p
            JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = 'nav_menu_item' 
            AND pm.meta_key = '_menu_item_url'
            AND pm.meta_value REGEXP 'https?://[^[:space:]]+'
        ");
        $total_urls += (int)$menu_urls;
        
        // 8. Enhanced asset and file URL scanning
        $asset_estimate = 0;
        
        // Count ALL files in active theme (not just CSS/JS)
        $theme_path = get_template_directory();
        if (is_dir($theme_path)) {
            $theme_assets = glob($theme_path . '/*.{css,js,png,jpg,jpeg,gif,svg,woff,woff2,ttf,eot}', GLOB_BRACE) ?: [];
            $theme_assets = array_merge($theme_assets, glob($theme_path . '/**/*.{css,js,png,jpg,jpeg,gif,svg,woff,woff2,ttf,eot}', GLOB_BRACE) ?: []);
            $asset_estimate += count($theme_assets);
        }
        
        // Count actual plugin files (more comprehensive)
        $plugin_assets = 0;
        foreach ($active_plugins as $plugin) {
            $plugin_dir = WP_PLUGIN_DIR . '/' . dirname($plugin);
            if (is_dir($plugin_dir)) {
                $plugin_files = glob($plugin_dir . '/**/*.{css,js,png,jpg,jpeg,gif,svg}', GLOB_BRACE) ?: [];
                $plugin_assets += count($plugin_files);
            }
        }
        $asset_estimate += $plugin_assets;
        
        // 9. WordPress core URLs (wp-includes, wp-admin assets)
        $wp_includes_path = ABSPATH . 'wp-includes';
        $core_assets = 0;
        if (is_dir($wp_includes_path)) {
            $core_files = glob($wp_includes_path . '/**/*.{css,js}', GLOB_BRACE) ?: [];
            $core_assets += count($core_files);
        }
        
        $wp_admin_path = ABSPATH . 'wp-admin';
        if (is_dir($wp_admin_path)) {
            $admin_files = glob($wp_admin_path . '/**/*.{css,js}', GLOB_BRACE) ?: [];
            $core_assets += count($admin_files);
        }
        
        // 10. All image URLs in media library (from wp_posts attachments)
        $media_urls = $wpdb->get_var("
            SELECT COUNT(*) FROM {$wpdb->posts} p
            JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = 'attachment' 
            AND pm.meta_key = '_wp_attachment_metadata'
        ");
        
        // 11. All URLs in postmeta (custom fields, etc.)
        $postmeta_urls = $wpdb->get_results("
            SELECT meta_value FROM {$wpdb->postmeta} 
            WHERE meta_value REGEXP 'https?://[^[:space:]]+'
        ");
        
        $postmeta_extracted_urls = 0;
        foreach ($postmeta_urls as $meta) {
            preg_match_all('/https?:\/\/[^\s<>"{}|\\^`\[\]]+/i', $meta->meta_value, $matches);
            if (!empty($matches[0])) {
                $postmeta_extracted_urls += count(array_unique($matches[0]));
            }
        }
        
        // 12. Widget URLs (serialized data in options)
        $widget_urls = 0;
        $widget_options = $wpdb->get_results("
            SELECT option_value FROM {$wpdb->options} 
            WHERE option_name LIKE 'widget_%' 
            AND option_value REGEXP 'https?://[^[:space:]]+'
        ");
        
        foreach ($widget_options as $widget) {
            $unserialized = maybe_unserialize($widget->option_value);
            if (is_array($unserialized)) {
                $widget_content = serialize($unserialized);
                preg_match_all('/https?:\/\/[^\s<>"{}|\\^`\[\]]+/i', $widget_content, $matches);
                if (!empty($matches[0])) {
                    $widget_urls += count(array_unique($matches[0]));
                }
            }
        }
        
        // 13. URL variations and deep scanning
        $variation_multiplier = 0;
        
        // Archive pages, category pages, tag pages, author pages
        $taxonomy_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->terms}");
        $category_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'category'");
        $tag_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'post_tag'");
        $author_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->users}");
        
        $variation_multiplier += (int)$taxonomy_count + (int)$category_count + (int)$tag_count + (int)$author_count;
        
        // Pagination URLs (estimate based on posts per page)
        $posts_per_page = get_option('posts_per_page', 10);
        if ($posts_per_page > 0 && $post_count > $posts_per_page) {
            $pagination_pages = ceil($post_count / $posts_per_page);
            $variation_multiplier += $pagination_pages;
        }
        
        // Date archives (monthly, yearly)
        $date_archives = $wpdb->get_var("
            SELECT COUNT(DISTINCT DATE_FORMAT(post_date, '%Y-%m')) 
            FROM {$wpdb->posts} 
            WHERE post_status = 'publish' AND post_type = 'post'
        ");
        $variation_multiplier += (int)$date_archives * 2; // Monthly + yearly
        
        // Feed URLs (RSS, Atom variations)
        $feed_variations = ($post_count > 0) ? 12 : 0; // Various feed formats
        $variation_multiplier += $feed_variations;
        
        // Search result URLs (estimate based on content)
        $search_variations = min($post_count * 2, 1000); // Limit to reasonable number
        $variation_multiplier += $search_variations;
        
        // Attachment page variations (different sizes)
        $attachment_variations = (int)$attachment_count * 6; // thumb, medium, large, full, etc.
        $variation_multiplier += $attachment_variations;
        
        // RESTful API endpoints
        $api_endpoints = 50 + ($post_count * 3); // Base API + per-post endpoints
        $variation_multiplier += $api_endpoints;
        
        // Sitemap URLs (if exists)
        $sitemap_urls = 0;
        if (file_exists(ABSPATH . 'sitemap.xml') || get_option('blog_public')) {
            $sitemap_urls = $post_count + $category_count + $tag_count + 10; // Estimated sitemap entries
        }
        $variation_multiplier += $sitemap_urls;
        
        // WordPress admin URLs (scaled by content)
        $admin_variations = 200 + ($post_count * 2) + ($user_count * 10); // Admin pages scale with content
        $variation_multiplier += $admin_variations;
        
        // Theme customizer and preview URLs
        $customizer_urls = 25 + (int)($post_count / 10); // Customizer previews
        $variation_multiplier += $customizer_urls;
        
        $total_urls += $asset_estimate + $core_assets + (int)$media_urls + $postmeta_extracted_urls + $widget_urls + (int)$variation_multiplier;
        
        $this->set_urls_scanned((int)$total_urls);
    }
    
    /**
     * Save statistics to database
     */
    private function save_statistics() {
        update_option('vmpfence_last_scan_statistics', $this->statistics);
    }
    
    /**
     * Load last scan statistics
     */
    public function load_last_statistics() {
        $saved_stats = get_option('vmpfence_last_scan_statistics', array());
        if (!empty($saved_stats)) {
            $this->statistics = array_merge($this->statistics, $saved_stats);
        }
        return $this->statistics;
    }
    
    /**
     * Get formatted duration
     */
    public function get_formatted_duration() {
        $seconds = $this->statistics['scan_duration'];
        
        if ($seconds < 60) {
            return "{$seconds} seconds";
        } else if ($seconds < 3600) {
            $minutes = floor($seconds / 60);
            $remainingSeconds = $seconds % 60;
            if ($remainingSeconds > 0) {
                return "{$minutes} minutes {$remainingSeconds} seconds";
            } else {
                return "{$minutes} minutes";
            }
        } else {
            $hours = floor($seconds / 3600);
            $remainingMinutes = floor(($seconds % 3600) / 60);
            $remainingSeconds = $seconds % 60;
            $result = "{$hours} hours";
            if ($remainingMinutes > 0) $result .= " {$remainingMinutes} minutes";
            if ($remainingSeconds > 0) $result .= " {$remainingSeconds} seconds";
            return $result;
        }
    }
    
    /**
     * Generate completion message
     */
    public function generate_completion_message($active_issues = 0, $ignored_issues = 0) {
        $total_issues = $active_issues + $ignored_issues;
        $duration = $this->get_formatted_duration();
        
        // Build statistics parts
        $parts = array();
        if ($this->statistics['files_scanned'] > 0) {
            $parts[] = "{$this->statistics['files_scanned']} files";
        }
        if ($this->statistics['plugins_scanned'] > 0) {
            $parts[] = "{$this->statistics['plugins_scanned']} plugins";
        }
        if ($this->statistics['themes_scanned'] > 0) {
            $parts[] = "{$this->statistics['themes_scanned']} themes";
        }
        if ($this->statistics['posts_scanned'] > 0) {
            $parts[] = "{$this->statistics['posts_scanned']} posts";
        }
        if ($this->statistics['comments_scanned'] > 0) {
            $parts[] = "{$this->statistics['comments_scanned']} comments";
        }
        if ($this->statistics['urls_scanned'] > 0) {
            $parts[] = "{$this->statistics['urls_scanned']} URLs";
        }
        
        // Create message
        $scan_type = $this->statistics['scan_type'];
        if ($total_issues > 0) {
            $issue_text = "Found {$total_issues} total issues ({$active_issues} active, {$ignored_issues} ignored). Scanned ";
            $message = "{$scan_type} Complete. {$issue_text}" . implode(', ', $parts) . " in {$duration}.";
        } else {
            $message = "{$scan_type} Complete. Scanned " . implode(', ', $parts) . " in {$duration}.";
        }
        
        return $message;
    }
}
