<?php
/**
 * Data Scanner Class
 *
 * Scans the database to find actual data stored by modules
 *
 * @package Switchboard
 * @since 1.0.0
 */

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

class Switchboard_Data_Scanner {

    /**
     * Scan all registered data and return what's actually in the database
     *
     * @param string $filter Optional filter: 'all', 'active', or 'inactive'
     * @return array Found data with counts
     */
    public function scan_all_data($filter = 'all') {
        $registry = Switchboard_Data_Registry::get_instance();

        // CRITICAL: Load ALL modules (including inactive ones) to register their data
        // This ensures we can find and clean data from previously enabled modules
        $registry->load_all_modules_for_cleanup();

        $registered = $registry->get_all_registered_data();

        // Filter by active/inactive modules if requested
        if ($filter !== 'all') {
            $registered = $this->filter_modules_by_status($registered, $filter);
        }

        $found = [
            'options' => $this->scan_options_from_registry($registered),
            'tables' => $this->scan_tables_from_registry($registered),
            'post_meta' => $this->scan_post_meta_from_registry($registered),
            'user_meta' => $this->scan_user_meta_from_registry($registered),
            'summary' => [],
        ];

        // Calculate summary
        $found['summary'] = [
            'total_options' => count($found['options']),
            'total_tables' => count($found['tables']),
            'total_post_meta_keys' => count($found['post_meta']),
            'total_user_meta_keys' => count($found['user_meta']),
            'estimated_size_mb' => $this->estimate_size($found),
        ];

        return $found;
    }

    /**
     * Filter modules by active/inactive status
     *
     * @param array $registered All registered modules
     * @param string $filter 'active' or 'inactive'
     * @return array Filtered modules
     */
    private function filter_modules_by_status($registered, $filter) {
        $active_modules = get_option('switchboard_active_modules', []);
        $filtered = [];

        foreach ($registered as $module_slug => $data) {
            $is_active = in_array($module_slug, $active_modules);

            if ($filter === 'active' && $is_active) {
                $filtered[$module_slug] = $data;
            } elseif ($filter === 'inactive' && !$is_active) {
                $filtered[$module_slug] = $data;
            }
        }

        return $filtered;
    }

    /**
     * Scan options table for registered options
     *
     * @param array $registered Registered data from registry
     * @return array Found options with values
     */
    private function scan_options_from_registry($registered) {
        global $wpdb;
        $found = [];

        foreach ($registered as $module_slug => $data) {
            // Scan exact option names
            foreach ($data['options'] as $option_name) {
                $value = get_option($option_name, null);
                if ($value !== null) {
                    $found[$option_name] = [
                        'module' => $module_slug,
                        'size' => strlen(maybe_serialize($value)),
                        'type' => 'exact',
                    ];
                }
            }

            // Scan option patterns
            foreach ($data['option_patterns'] as $pattern) {
                $results = $wpdb->get_results($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    "SELECT option_name, LENGTH(option_value) as size
                    FROM {$wpdb->options}
                    WHERE option_name LIKE %s",
                    $pattern
                ), ARRAY_A);

                foreach ($results as $row) {
                    $found[$row['option_name']] = [
                        'module' => $module_slug,
                        'size' => (int) $row['size'],
                        'type' => 'pattern',
                    ];
                }
            }
        }

        return $found;
    }

    /**
     * Scan for registered tables
     *
     * @param array $registered Registered data from registry
     * @return array Found tables with info
     */
    private function scan_tables_from_registry($registered) {
        global $wpdb;
        $found = [];

        foreach ($registered as $module_slug => $data) {
            foreach ($data['tables'] as $table_name) {
                $full_table_name = $wpdb->prefix . $table_name;

                // Defense-in-depth: Escape table name
                $escaped_table_name = esc_sql($full_table_name);

                // Check if table exists
                $exists = $wpdb->get_var("SHOW TABLES LIKE '{$escaped_table_name}'"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

                if ($exists) {
                    // Get row count
                    $row_count = $wpdb->get_var("SELECT COUNT(*) FROM {$escaped_table_name}"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

                    // Get table size
                    $size_query = $wpdb->get_row($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                        "SELECT
                            ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb,
                            table_rows
                        FROM information_schema.TABLES
                        WHERE table_schema = %s
                        AND table_name = %s",
                        DB_NAME,
                        $full_table_name
                    ));

                    $found[$table_name] = [
                        'module' => $module_slug,
                        'full_name' => $full_table_name,
                        'rows' => (int) $row_count,
                        'size_mb' => $size_query ? (float) $size_query->size_mb : 0,
                    ];
                }
            }
        }

        return $found;
    }

    /**
     * Scan for registered post meta
     *
     * @param array $registered Registered data from registry
     * @return array Found post meta keys with counts
     */
    private function scan_post_meta_from_registry($registered) {
        global $wpdb;
        $found = [];

        foreach ($registered as $module_slug => $data) {
            foreach ($data['post_meta'] as $meta_key) {
                $count = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key = %s",
                    $meta_key
                ));

                if ($count > 0) {
                    $found[$meta_key] = [
                        'module' => $module_slug,
                        'count' => (int) $count,
                    ];
                }
            }
        }

        return $found;
    }

    /**
     * Scan for registered user meta
     *
     * @param array $registered Registered data from registry
     * @return array Found user meta keys with counts
     */
    private function scan_user_meta_from_registry($registered) {
        global $wpdb;
        $found = [];

        foreach ($registered as $module_slug => $data) {
            foreach ($data['user_meta'] as $meta_key) {
                $count = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    "SELECT COUNT(*) FROM {$wpdb->usermeta} WHERE meta_key = %s",
                    $meta_key
                ));

                if ($count > 0) {
                    $found[$meta_key] = [
                        'module' => $module_slug,
                        'count' => (int) $count,
                    ];
                }
            }
        }

        return $found;
    }

    /**
     * Estimate total data size
     *
     * @param array $found Found data
     * @return float Size in MB
     */
    private function estimate_size($found) {
        $total_bytes = 0;

        // Options size
        foreach ($found['options'] as $option) {
            $total_bytes += $option['size'];
        }

        // Tables size (already in MB)
        $table_mb = 0;
        foreach ($found['tables'] as $table) {
            $table_mb += $table['size_mb'];
        }

        // Post meta estimate (avg 500 bytes per entry)
        foreach ($found['post_meta'] as $meta) {
            $total_bytes += $meta['count'] * 500;
        }

        // User meta estimate (avg 300 bytes per entry)
        foreach ($found['user_meta'] as $meta) {
            $total_bytes += $meta['count'] * 300;
        }

        $total_mb = ($total_bytes / 1024 / 1024) + $table_mb;

        return round($total_mb, 2);
    }

    /**
     * Get detailed breakdown by module
     *
     * @return array Module-wise data breakdown
     */
    public function get_module_breakdown() {
        $all_data = $this->scan_all_data();
        $breakdown = [];

        // Group by module
        foreach ($all_data['options'] as $name => $info) {
            $module = $info['module'];
            if (!isset($breakdown[$module])) {
                $breakdown[$module] = [
                    'options' => [],
                    'tables' => [],
                    'post_meta' => [],
                    'user_meta' => [],
                ];
            }
            $breakdown[$module]['options'][] = $name;
        }

        foreach ($all_data['tables'] as $name => $info) {
            $module = $info['module'];
            if (!isset($breakdown[$module])) {
                $breakdown[$module] = [
                    'options' => [],
                    'tables' => [],
                    'post_meta' => [],
                    'user_meta' => [],
                ];
            }
            $breakdown[$module]['tables'][] = $name;
        }

        return $breakdown;
    }
}
