<?php

declare(strict_types=1);

namespace ShieldX\WPCLI;

defined('ABSPATH') || exit;

use ShieldX\Core\Plugin;

final class LockdownCommand
{
    private const CLI_WRITE_NONCE_ACTION = 'shieldx_cli_lockdown_write';

    /** @var Plugin */
    private $plugin;

    public function __construct(Plugin $plugin)
    {
        $this->plugin = $plugin;
    }

    /**
     * Inspect, preview, apply, or revert SHIELD-X Lockdown.
     *
     * @synopsis [<status|preview|enable|disable|revert|reapply>] [--aggressive] [--format=<format>] [--yes]
     *
     * @param array<int,string> $args
     * @param array<string,mixed> $assocArgs
     */
    public function __invoke(array $args, array $assocArgs): void
    {
        AdminGate::requireManageOptions();

        $subcommand = isset($args[0]) ? (string) $args[0] : 'status';
        $json = CommandOutput::isJson($assocArgs);

        switch ($subcommand) {
            case 'status':
                $this->status($json);
                return;

            case 'preview':
                $this->preview($json);
                return;

            case 'enable':
                $this->enable($assocArgs, $json);
                return;

            case 'disable':
            case 'revert':
                $this->disable($assocArgs, $json);
                return;

            case 'reapply':
                $this->reapply($assocArgs, $json);
                return;

            default:
                \WP_CLI::error('Unknown lockdown command. Use status, preview, enable, disable, revert, or reapply.');
        }
    }

    private function status(bool $json): void
    {
        $status = $this->plugin->lockdownStatus();
        $coverage = isset($status['coverage']) && is_array($status['coverage']) ? $status['coverage'] : [];
        if ($json) {
            CommandOutput::writeJson([
                'command' => 'lockdown',
                'subcommand' => 'status',
                'status' => $status,
            ]);
            return;
        }

        \WP_CLI::line('Lockdown: ' . (!empty($status['enabled']) ? 'enabled' : 'disabled'));
        \WP_CLI::line('Manifest: ' . (!empty($status['manifest_exists']) ? (string) ($status['manifest_path'] ?? '') : 'not present'));
        \WP_CLI::line('Killswitch: ' . (!empty($status['killswitch_active']) ? 'active' : 'inactive'));
        \WP_CLI::line('Exec block: ' . (string) ($coverage['exec_block'] ?? 'unknown'));
        \WP_CLI::line('Read-only: ' . (string) ($coverage['readonly'] ?? 'unknown'));
        \WP_CLI::line('Update/install lock: ' . (string) ($coverage['editor_lock'] ?? 'unknown'));
        \WP_CLI::line('Coverage: ' . (string) ($coverage['message'] ?? ''));
        \WP_CLI::success('SHIELD-X lockdown status completed.');
    }

    private function preview(bool $json): void
    {
        $preview = $this->plugin->previewLockdown();
        $summary = isset($preview['summary']) && is_array($preview['summary']) ? $preview['summary'] : [];
        if ($json) {
            CommandOutput::writeJson([
                'command' => 'lockdown',
                'subcommand' => 'preview',
                'preview' => $preview,
                'summary' => $summary,
            ]);
            return;
        }

        \WP_CLI::line('Lockdown preview');
        \WP_CLI::line('Actions: ' . (string) ($summary['actions'] ?? 0));
        \WP_CLI::line('Read-only paths: ' . (string) ($summary['read_only_paths'] ?? 0));
        \WP_CLI::line('No-exec dirs: ' . (string) ($summary['no_exec_dirs'] ?? 0));

        foreach ((array) ($preview['actions'] ?? []) as $action) {
            if (!is_array($action)) {
                continue;
            }

            \WP_CLI::line(sprintf(
                '- %s %s [%s]',
                (string) ($action['type'] ?? ''),
                (string) ($action['path'] ?? ''),
                (string) ($action['status'] ?? '')
            ));
        }

        \WP_CLI::success('SHIELD-X lockdown preview completed.');
    }

    /**
     * @param array<string,mixed> $assocArgs
     */
    private function enable(array $assocArgs, bool $json): void
    {
        \WP_CLI::confirm('Apply SHIELD-X filesystem lockdown changes?', $assocArgs);

        $policy = [];
        if (!empty($assocArgs['aggressive'])) {
            $status = $this->plugin->lockdownStatus();
            $savedPolicy = isset($status['policy']) && is_array($status['policy']) ? $status['policy'] : [];
            $policy = array_replace($savedPolicy, [
                'disable_file_mods' => true,
            ]);
        }

        $result = $this->withCliWriteAuthorization(function () use ($policy): array {
            return $this->plugin->applyLockdown($policy, true, true, self::CLI_WRITE_NONCE_ACTION);
        });
        if (empty($result['ok'])) {
            \WP_CLI::error((string) ($result['message'] ?? 'Lockdown failed.'));
        }

        if ($json) {
            CommandOutput::writeJson([
                'command' => 'lockdown',
                'subcommand' => 'enable',
                'result' => $result,
            ]);
            return;
        }

        \WP_CLI::success((string) ($result['message'] ?? 'SHIELD-X lockdown enabled.'));
    }

    /**
     * @param array<string,mixed> $assocArgs
     */
    private function disable(array $assocArgs, bool $json): void
    {
        \WP_CLI::confirm('Revert SHIELD-X filesystem lockdown changes?', $assocArgs);
        $result = $this->plugin->revertLockdown(true);
        if (empty($result['ok'])) {
            \WP_CLI::error((string) ($result['message'] ?? 'Lockdown revert failed.'));
        }

        if ($json) {
            CommandOutput::writeJson([
                'command' => 'lockdown',
                'subcommand' => 'revert',
                'result' => $result,
            ]);
            return;
        }

        \WP_CLI::success((string) ($result['message'] ?? 'SHIELD-X lockdown reverted.'));
    }

    /**
     * @param array<string,mixed> $assocArgs
     */
    private function reapply(array $assocArgs, bool $json): void
    {
        \WP_CLI::confirm('Reapply SHIELD-X filesystem lockdown changes?', $assocArgs);
        $result = $this->withCliWriteAuthorization(function (): array {
            return $this->plugin->reapplyLockdownForAuthorizedRequest(true, self::CLI_WRITE_NONCE_ACTION);
        });
        if (empty($result['ok'])) {
            \WP_CLI::error((string) ($result['message'] ?? 'Lockdown reapply failed.'));
        }

        if ($json) {
            CommandOutput::writeJson([
                'command' => 'lockdown',
                'subcommand' => 'reapply',
                'result' => $result,
            ]);
            return;
        }

        \WP_CLI::success((string) ($result['message'] ?? 'SHIELD-X lockdown reapplied.'));
    }

    /**
     * Scope the core WP-CLI write signal to a command that has just passed
     * WP_CLI::confirm(). It is restored even when the write fails, so an
     * unrelated direct wp eval in this PHP process remains blocked by default.
     *
     * @param callable():array<string,mixed> $operation
     * @return array<string,mixed>
     */
    private function withCliWriteAuthorization(callable $operation): array
    {
        if (!function_exists('putenv')) {
            return [
                'ok' => false,
                'status' => 'cli_confirmation_unavailable',
                'message' => 'WP-CLI write confirmation is unavailable because putenv() is disabled.',
            ];
        }

        $previousConfirmation = getenv('SHIELDX_CLI_CONFIRM');
        putenv('SHIELDX_CLI_CONFIRM=yes');

        try {
            return $operation();
        } finally {
            if ($previousConfirmation === false) {
                putenv('SHIELDX_CLI_CONFIRM');
            } else {
                putenv('SHIELDX_CLI_CONFIRM=' . $previousConfirmation);
            }
        }
    }

}
