<?php

declare(strict_types=1);

namespace ShieldX\WPCLI;

defined('ABSPATH') || exit;

use ShieldX\Core\Plugin;

final class StatusCommand
{
    /** @var Plugin */
    private $plugin;

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

    /**
     * Print a compact SHIELD-X status summary.
     *
     * @synopsis [--format=<format>]
     *
     * @param array<int,string> $args
     * @param array<string,mixed> $assocArgs
     */
    public function __invoke(array $args, array $assocArgs): void
    {
        AdminGate::requireManageOptions();

        $status = $this->plugin->status();

        if (CommandOutput::isJson($assocArgs)) {
            CommandOutput::writeJson([
                'command' => 'status',
                'status' => $status,
            ]);
            return;
        }

        \WP_CLI::line('SHIELD-X ' . $status['plugin']['version']);
        \WP_CLI::line('Tier: ' . $status['environment']['tier']);
        \WP_CLI::line('WAF: ' . $status['waf']['mode']);
        \WP_CLI::line('WAF engine: ' . ($status['waf']['engine_version'] ?? 'unknown'));
        \WP_CLI::line('Rules: ' . (string) ($status['waf']['rules_enabled'] ?? 0) . '/' . (string) ($status['waf']['rules_loaded'] ?? 0));
        \WP_CLI::line('Categories: ' . self::formatCounts((array) ($status['waf']['category_counts'] ?? [])));
        \WP_CLI::line('Severities: ' . self::formatCounts((array) ($status['waf']['severity_counts'] ?? [])));
        \WP_CLI::line('Hide WP signature: ' . (!empty($status['hardening']['hide_wordpress_signature']) ? 'enabled' : 'disabled'));
        \WP_CLI::line('Force SSL: ' . (!empty($status['hardening']['force_ssl_enabled']) ? 'enabled' : 'disabled'));
        \WP_CLI::line('File editor: ' . (!empty($status['hardening']['disable_file_edit']) ? 'disabled' : 'enabled'));
        $responseHeaders = isset($status['hardening']['response_headers']) && is_array($status['hardening']['response_headers'])
            ? $status['hardening']['response_headers']
            : [];
        \WP_CLI::line('Response headers: ' . count(array_filter($responseHeaders)) . '/' . count($responseHeaders) . ' enabled');
        \WP_CLI::line('Admin gate: ' . (!empty($status['hardening']['admin_gate_enabled']) ? 'enabled' : 'disabled'));
        \WP_CLI::line('Lockdown: ' . self::formatLockdown((array) ($status['lockdown'] ?? [])));
        \WP_CLI::line('Login security: ' . self::formatLoginSecurity((array) ($status['login_security'] ?? [])));
        \WP_CLI::line('Rate limit: ' . self::formatRateLimit((array) ($status['rate_limit']['request'] ?? [])));
        \WP_CLI::line('Login protection: ' . self::formatLoginProtection((array) ($status['rate_limit']['login'] ?? [])));
        \WP_CLI::line('Scanner: ' . self::formatScanner((array) ($status['scanner'] ?? [])));
        \WP_CLI::line('Vulnerability scanner: ' . self::formatVulnerabilityScanner((array) ($status['scanner']['vulnerability'] ?? [])));
        \WP_CLI::line('Scheduled scanner: ' . self::formatScheduledScanner((array) ($status['scanner']['schedule'] ?? [])));
        \WP_CLI::line('Scheduled backup: ' . self::formatScheduledBackup((array) ($status['maintenance']['database_backups']['schedule'] ?? [])));
        \WP_CLI::line('Scheduled restore point: ' . self::formatScheduledRestorePoint((array) ($status['maintenance']['restore_points']['schedule'] ?? [])));
        \WP_CLI::line('Backup storage: ' . self::formatBackupStorage((array) ($status['maintenance']['backup_storage'] ?? [])));
        \WP_CLI::line('Compatibility: ' . self::formatCompatibility((array) ($status['environment']['compatibility']['summary'] ?? [])));
        \WP_CLI::line('Storage: ' . ($status['health']['storage_ready'] ? 'ready' : 'blocked'));
        \WP_CLI::line('Schema: ' . ($status['health']['schema_ready'] ? 'ready' : 'pending'));
        \WP_CLI::success('SHIELD-X status check completed.');
    }

    /**
     * @param array<string,int> $counts
     */
    private static function formatCounts(array $counts): string
    {
        $parts = [];

        foreach ($counts as $label => $count) {
            $parts[] = (string) $label . '=' . (string) $count;
        }

        return $parts ? implode(', ', $parts) : 'none';
    }

    /**
     * @param array<string,mixed> $lockdown
     */
    private static function formatLockdown(array $lockdown): string
    {
        $coverage = isset($lockdown['coverage']) && is_array($lockdown['coverage']) ? $lockdown['coverage'] : [];

        return sprintf(
            '%s, exec=%s, readonly=%s',
            empty($lockdown['enabled']) ? 'disabled' : 'enabled',
            (string) ($coverage['exec_block'] ?? 'unknown'),
            (string) ($coverage['readonly'] ?? 'unknown')
        );
    }

    /**
     * @param array<string,mixed> $loginSecurity
     */
    private static function formatLoginSecurity(array $loginSecurity): string
    {
        if (empty($loginSecurity['enabled'])) {
            return 'disabled';
        }

        return sprintf(
            '2FA %s, required users %s/%s enrolled, sessions=%s, magic=%s, recovery=%s',
            empty($loginSecurity['two_factor_required_roles']) ? 'optional' : 'required',
            (string) ($loginSecurity['required_users_enrolled'] ?? 0),
            (string) ($loginSecurity['required_users_total'] ?? 0),
            empty($loginSecurity['session_policy_enabled']) ? 'optional' : 'protected',
            empty($loginSecurity['magic_login_enabled']) ? 'off' : 'on',
            (string) ($loginSecurity['recovery_email'] ?? '')
        );
    }

    /**
     * @param array<string,mixed> $request
     */
    private static function formatRateLimit(array $request): string
    {
        if (empty($request['enabled'])) {
            return 'disabled';
        }

        return sprintf(
            '%s, %s/%ss, burst %s/%ss',
            (string) ($request['mode'] ?? 'log_only'),
            (string) ($request['limit'] ?? 0),
            (string) ($request['window_seconds'] ?? 0),
            (string) ($request['burst_limit'] ?? 0),
            (string) ($request['burst_window_seconds'] ?? 0)
        );
    }

    /**
     * @param array<string,mixed> $login
     */
    private static function formatLoginProtection(array $login): string
    {
        if (empty($login['enabled'])) {
            return 'disabled';
        }

        return sprintf(
            '%s failures/%ss, lockout %ss',
            (string) ($login['failure_limit'] ?? 0),
            (string) ($login['window_seconds'] ?? 0),
            (string) ($login['lockout_seconds'] ?? 0)
        );
    }

    /**
     * @param array<string,mixed> $scanner
     */
    private static function formatScanner(array $scanner): string
    {
        $lastScan = isset($scanner['last_scan']) && is_array($scanner['last_scan']) ? $scanner['last_scan'] : null;
        $last = $lastScan
            ? sprintf(
                '%s at %s, scope=%s, scanned=%s, skipped=%s, hash_checks=%s%s',
                (string) ($lastScan['status'] ?? 'unknown'),
                (string) ($lastScan['started_at'] ?? 'unknown'),
                (string) ($lastScan['scope'] ?? 'all'),
                (string) ($lastScan['files_scanned'] ?? 0),
                (string) ($lastScan['files_skipped'] ?? 0),
                (string) ($lastScan['files_hash_checked'] ?? 0),
                !empty($lastScan['database_selected'])
                    ? ', db_checks=' . (string) ($lastScan['database_items_scanned'] ?? 0) . ', db_issues=' . (string) ($lastScan['database_issues_found'] ?? 0)
                    : ''
            )
            : 'never';

        return sprintf(
            '%s, active issues=%s, tracked files=%s, last=%s',
            (string) ($scanner['mode'] ?? 'local_quick_scan'),
            (string) ($scanner['active_issues'] ?? 0),
            (string) ($scanner['tracked_files'] ?? 0),
            $last
        );
    }

    /**
     * @param array<string,mixed> $vulnerability
     */
    private static function formatVulnerabilityScanner(array $vulnerability): string
    {
        return sprintf(
            '%s, last=%s, issues=%s, updates=%s, stale=%s, abandoned=%s, risky=%s, advisories=%s, software=%s/%s detected, software_advisories=%s, virtual_patches=%s, feed=%s/%s',
            (string) ($vulnerability['engine_version'] ?? 'unknown'),
            (string) ($vulnerability['last_scan_at'] ?? 'never'),
            (string) ($vulnerability['issues_found'] ?? 0),
            (string) ($vulnerability['updates_found'] ?? 0),
            (string) ($vulnerability['stale_plugins'] ?? 0),
            (string) ($vulnerability['abandoned_plugins'] ?? 0),
            (string) ($vulnerability['risky_version_ranges'] ?? 0),
            (string) ($vulnerability['advisory_hits'] ?? 0),
            (string) ($vulnerability['software_detected'] ?? 0),
            (string) ($vulnerability['software_total'] ?? 0),
            (string) ($vulnerability['software_advisory_hits'] ?? 0),
            (string) ($vulnerability['virtual_patch_recommendations'] ?? 0),
            (string) ($vulnerability['advisory_cache']['source'] ?? 'none'),
            (string) ($vulnerability['advisory_cache']['records_total'] ?? 0)
        );
    }

    /**
     * @param array<string,mixed> $schedule
     */
    private static function formatScheduledScanner(array $schedule): string
    {
        $sections = isset($schedule['sections']) && is_array($schedule['sections']) ? $schedule['sections'] : [];
        if ($sections) {
            $parts = [];
            foreach (['file', 'database', 'vulnerability'] as $type) {
                $section = isset($sections[$type]) && is_array($sections[$type]) ? $sections[$type] : [];
                $wpCron = empty($section['enabled']) ? 'off' : (string) ($section['recurrence'] ?? 'daily');
                $external = empty($section['external_runner_enabled']) ? 'external off' : 'external on';
                $next = !empty($section['next_run']) ? ', next=' . (string) $section['next_run'] : '';
                $parts[] = $type . ': ' . $wpCron . ', ' . $external . $next;
            }

            return implode(' | ', $parts);
        }

        $wpCron = empty($schedule['enabled']) ? 'wp-cron disabled' : 'wp-cron ' . (string) ($schedule['recurrence'] ?? 'daily');
        $external = empty($schedule['external_runner_enabled']) ? 'external disabled' : 'external enabled';
        $next = !empty($schedule['next_run']) ? ', next=' . (string) $schedule['next_run'] : '';

        return $wpCron . ', ' . $external . $next;
    }

    /**
     * @param array<string,mixed> $schedule
     */
    private static function formatScheduledBackup(array $schedule): string
    {
        $wpCron = empty($schedule['enabled']) ? 'wp-cron disabled' : 'wp-cron ' . (string) ($schedule['recurrence'] ?? 'daily');
        $external = empty($schedule['external_runner_enabled']) ? 'external disabled' : 'external enabled';
        $next = !empty($schedule['next_run']) ? ', next=' . (string) $schedule['next_run'] : '';
        $last = !empty($schedule['last_run_at']) ? ', last=' . (string) $schedule['last_run_at'] : ', last=never';

        return $wpCron . ', ' . $external . $next . $last;
    }

    /**
     * @param array<string,mixed> $schedule
     */
    private static function formatScheduledRestorePoint(array $schedule): string
    {
        $wpCron = empty($schedule['enabled']) ? 'wp-cron disabled' : 'wp-cron ' . (string) ($schedule['recurrence'] ?? 'daily');
        $external = empty($schedule['external_runner_enabled']) ? 'external disabled' : 'external enabled';
        $next = !empty($schedule['next_run']) ? ', next=' . (string) $schedule['next_run'] : '';
        $last = !empty($schedule['last_run_at']) ? ', last=' . (string) $schedule['last_run_at'] : ', last=never';
        $restoreId = !empty($schedule['last_restore_id']) ? ', restore=' . (string) $schedule['last_restore_id'] : '';

        return $wpCron . ', ' . $external . $next . $last . $restoreId;
    }

    /**
     * @param array<string,mixed> $storage
     */
    private static function formatBackupStorage(array $storage): string
    {
        $mode = (string) ($storage['mode'] ?? 'local');
        $google = isset($storage['google']) && is_array($storage['google']) ? $storage['google'] : [];
        if ($mode === 'local') {
            return 'local';
        }

        if (empty($google['credentials_available'])) {
            return $mode . ', google unavailable';
        }

        if (empty($google['secret_storage_ready'])) {
            return $mode . ', token encryption unavailable';
        }

        return $mode . ', google ' . (empty($google['connected']) ? 'disconnected' : 'connected');
    }

    /**
     * @param array<string,mixed> $summary
     */
    private static function formatCompatibility(array $summary): string
    {
        return sprintf(
            '%s, checks ready=%s warning=%s missing=%s, modules ready=%s warning=%s missing=%s',
            (string) ($summary['status'] ?? 'unknown'),
            (string) ($summary['ready'] ?? 0),
            (string) ($summary['warning'] ?? 0),
            (string) ($summary['missing'] ?? 0),
            (string) ($summary['module_ready'] ?? 0),
            (string) ($summary['module_warning'] ?? 0),
            (string) ($summary['module_missing'] ?? 0)
        );
    }
}
