<?php

declare(strict_types=1);

namespace ReallySimplePlugins\RSS\Core\Features\Pro\Vulnerability\Services;

/**
 * Quarantines vulnerable plugins or themes by renaming their directory or file.
 *
 * This service is triggered by the vulnerability measures workflow when a
 * component must be isolated instead of updated.
 *
 * High-level flow:
 * 1) Ensure an admin is logged in (safety guard).
 * 2) Determine whether the component is a plugin or a theme.
 * 3) Resolve the most accurate filesystem path for that component.
 * 4) Rename the directory or file by appending a quarantine suffix.
 *
 * Notes for juniors:
 * - Quarantine is implemented as a filesystem rename; nothing is deleted.
 * - A random suffix is added to avoid name collisions and allow repeated quarantines.
 * - This method intentionally fails silently to avoid breaking admin requests.
 */
final class VulnerabilityQuarantineService
{
    /**
     * Quarantine a vulnerable component.
     *
     * The `$measure` array is provided by the vulnerability measures pipeline
     * and describes the affected component.
     *
     * Expected shape:
     * @param array{
     *   type: 'plugin'|'theme',
     *   component_slug: string,
     *   plugin_file?: string
     * } $measure
     *
     * Behaviour overview:
     * - Themes are quarantined by renaming their theme directory.
     * - Plugins are quarantined by renaming either:
     *   - the plugin directory (preferred), or
     *   - the plugin file for single-file plugins.
     */
    public function quarantine(array $measure): void
    {
        // Safety guard: only allow quarantine actions for logged-in admins.
        if (!function_exists('rsssl_admin_logged_in') || !rsssl_admin_logged_in()) {
            return;
        }

        $type = (string)($measure['type'] ?? '');
        $slug = (string)($measure['component_slug'] ?? '');
        $pluginFile = (string)($measure['plugin_file'] ?? '');

        $suffix = '-rsssl-q-' . $this->randomSuffix(6);

        // Theme quarantine: rename the theme directory.
        if ($type === 'theme') {
            if ($slug === '') {
                return;
            }

            $dir = trailingslashit((string) get_theme_root()) . $slug;
            if (is_dir($dir)) {
                @rename($dir, $dir . $suffix);
            }

            return;
        }

        // Plugin quarantine: resolve the most accurate path (file or directory).
        if ($type !== 'plugin') {
            return;
        }

        // Prefer plugin file when available (handles single-file plugins correctly).
        if ($pluginFile !== '') {
            $full = trailingslashit((string) WP_PLUGIN_DIR) . $pluginFile;

            // If plugin is in a folder, quarantine the folder.
            if (strpos($pluginFile, '/') !== false) {
                $folder = trailingslashit((string) WP_PLUGIN_DIR) . dirname($pluginFile);
                if (is_dir($folder)) {
                    @rename($folder, $folder . $suffix);
                }

                return;
            }

            // Single-file plugin.
            if (is_file($full)) {
                $new = str_replace('.php', '', $full) . $suffix . '.php';
                @rename($full, $new);
            }

            return;
        }

        // Fallback: quarantine plugin directory based on component slug.
        if ($slug === '') {
            return;
        }

        $dir = trailingslashit((string) WP_PLUGIN_DIR) . $slug;
        if (is_dir($dir)) {
            @rename($dir, $dir . $suffix);
        }
    }

    /**
     * Generate a random suffix used to mark quarantined components.
     *
     * Multiple strategies are used to stay compatible with different
     * environments and WordPress versions.
     */
    private function randomSuffix(int $length): string
    {
        if (function_exists('rsssl_generate_random_string')) {
            return (string) rsssl_generate_random_string($length);
        }

        if (function_exists('wp_generate_password')) {
            return strtolower((string) wp_generate_password($length, false, false));
        }

        return substr(md5((string) time()), 0, max(1, $length));
    }
}
