<?php

namespace WPUltimateSecurity\UltimateSecurity\Presentation\API\Controllers;

use WP_REST_Response;
use WP_REST_Request;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\DateHelper;

/**
 * Scanner Controller
 *
 * Handles file integrity scanning and WordPress core checks
 */
class ScannerController
{
    /**
     * Cache key for scan results
     */
    private const CACHE_KEY = 'ultimate_security_file_integrity_scan';

    /**
     * Cache duration in seconds (5 minutes)
     */
    private const CACHE_DURATION = 300;

    /**
     * Check WordPress core integrity
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|void
     */
    public static function check_integrity($request = null)
    {
        // Check for force refresh parameter
        $force_refresh = false;
        if ($request instanceof WP_REST_Request) {
            $force_refresh = $request->get_param('force_refresh') === '1' || $request->get_param('force_refresh') === 'true';
        }

        // Try to get cached results if not forcing refresh
        if (!$force_refresh) {
            $cached = get_transient(self::CACHE_KEY);
            if ($cached !== false) {
                return new WP_REST_Response($cached, 200);
            }
        }

        // Make sure the function is loaded
        if (!function_exists('get_core_checksums')) {
            require_once ABSPATH . 'wp-admin/includes/update.php';
        }

        $version = get_bloginfo('version');
        $locale = get_locale();

        // Cache WordPress checksums to avoid repeated API calls to wordpress.org
        $checksum_cache_key = 'ultimate_security_wp_checksums_' . md5($version . '_' . $locale);
        $checksums = get_transient($checksum_cache_key);

        if ($checksums === false) {
            $checksums = get_core_checksums($version, $locale);
            if ($checksums && is_array($checksums)) {
                // Cache checksums for 1 hour (they rarely change)
                set_transient($checksum_cache_key, $checksums, HOUR_IN_SECONDS);
            }
        }

        $get_local_files = self::get_local_files();

        // Remove the wp-content/ files from checking
        foreach ($checksums as $file => $checksum) {
            if (false !== strpos($file, 'wp-content/')) {
                unset($checksums[$file]);
            }
        }

        if (!$checksums || !is_array($checksums)) {
            return new WP_REST_Response([
                'success' => false,
                'error' => __('Unable to fetch WordPress checksums. Please check your internet connection.', 'ultimate-security'),
                'scan_time' => DateHelper::now(),
                'wordpress_version' => $version,
                'files' => [],
                'summary' => ['modified' => 0, 'missing' => 0, 'unknown' => 0, 'total' => 0],
            ], 200);
        }

        $errors = [];
        $scan_time = DateHelper::now();

        foreach ($checksums as $file => $expected_checksum) {
            $file_path = ABSPATH . $file;

            if (!file_exists($file_path)) {
                $errors[] = [
                    'file' => $file,
                    'reason' => 'Missing',
                    'size' => null,
                    'modified' => null,
                ];
                continue;
            }

            $actual_checksum = md5_file($file_path);
            if ($actual_checksum !== $expected_checksum) {
                $errors[] = [
                    'file' => $file,
                    'reason' => 'Modified',
                    'size' => filesize($file_path),
                    'modified' => date('Y-m-d H:i:s', filemtime($file_path)),
                ];
            }
        }

        foreach ($get_local_files as $file => $current_checksum) {
            // Convert full path to relative path for comparison
            $relative_path = str_replace('\\', '/', str_replace(ABSPATH, '', $file));

            if (!array_key_exists($relative_path, $checksums)) {
                $errors[] = [
                    'file' => $relative_path,
                    'reason' => 'Unknown',
                    'size' => file_exists($file) ? filesize($file) : null,
                    'modified' => file_exists($file) ? date('Y-m-d H:i:s', filemtime($file)) : null,
                ];
            }
        }

        // Calculate summary counts
        $summary = [
            'modified' => count(array_filter($errors, function($e) { return $e['reason'] === 'Modified'; })),
            'missing' => count(array_filter($errors, function($e) { return $e['reason'] === 'Missing'; })),
            'unknown' => count(array_filter($errors, function($e) { return $e['reason'] === 'Unknown'; })),
            'total' => count($errors),
        ];

        // Prepare response with metadata
        $response = [
            'success' => true,
            'scan_time' => $scan_time,
            'wordpress_version' => $version,
            'summary' => $summary,
            'files' => $errors,
        ];

        // Cache the results
        set_transient(self::CACHE_KEY, $response, self::CACHE_DURATION);

        return new WP_REST_Response($response, 200);
    }

    /**
     * Get local WordPress files
     *
     * @return array
     */
    private static function get_local_files()
    {
        $all_files = [];
        $get_wp_root_files = self::get_wp_root_files_only();

        foreach ($get_wp_root_files as $root_file) {
            $all_files[ABSPATH . $root_file] = md5_file(ABSPATH . $root_file);
        }

        $admin_files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator(ABSPATH . 'wp-admin'),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($admin_files as $file) {
            if ($file->isFile() && md5_file($file->getPathname())) {
                $all_files[$file->getPathname()] = md5_file($file->getPathname());
            }
        }

        $includes_files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator(ABSPATH . 'wp-includes'),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($includes_files as $file) {
            if ($file->isFile() && md5_file($file->getPathname())) {
                $all_files[$file->getPathname()] = md5_file($file->getPathname());
            }
        }

        return $all_files;
    }

    /**
     * Get WordPress root files only
     *
     * @return array
     */
    private static function get_wp_root_files_only()
    {
        $wp_root = ABSPATH;
        $exclude = ['wp-admin', 'wp-content', 'wp-includes', '.htaccess', 'wp-config.php'];

        $items = scandir($wp_root);

        $files = array_filter($items, function ($item) use ($wp_root, $exclude) {
            $path = $wp_root . $item;
            return is_file($path) &&
                $item != '.' &&
                $item != '..' &&
                !in_array($item, $exclude);
        });

        sort($files);

        return $files;
    }
}
