<?php

namespace VulnTitan\Services;

use VulnTitan\Api\Client;
use VulnTitan\Services\VulnerabilityRiskService;

class VulnerabilityScanner
{
    public function runScan(): void
    {
        check_ajax_referer('vulntitan_ajax_scan', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => esc_html__('Insufficient permissions.', 'vulntitan')], 403);
        }

        // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $item = isset($_POST['item']) ? (array) wp_unslash($_POST['item']) : null;
        $result = $this->scanItem($item);

        if (!($result['success'] ?? false)) {
            wp_send_json_error(['message' => $result['message'] ?? esc_html__('Unknown error occurred.', 'vulntitan')]);
        }

        wp_send_json_success([
            'message' => $result['message'],
            'vulnerabilities' => $result['vulnerabilities'],
            'meta' => $result['meta'] ?? [],
        ]);
    }

    public function scanItem(?array $item): array
    {
        $type = sanitize_key($item['type'] ?? '');
        $slug = sanitize_text_field($item['slug'] ?? '');
        $version = sanitize_text_field($item['version'] ?? '');
        $normalizedItem = [
            'type' => $type,
            'slug' => $slug,
            'version' => $version,
        ];

        if (!$item || !$type || !$version || ($type !== 'core' && !$slug)) {
            return [
                'success' => false,
                'message' => esc_html__('Invalid scan item.', 'vulntitan'),
                'vulnerabilities' => [],
            ];
        }

        $client = new Client();

        switch ($type) {
            case 'plugin':
                $result = $client->checkPlugin($slug, $version);
                break;
            case 'theme':
                $result = $client->checkTheme($slug, $version);
                break;
            case 'core':
                $result = $client->checkCore($version);
                break;
            default:
                $result = ['success' => false, 'message' => esc_html__('Unknown item type.', 'vulntitan'), 'vulnerabilities' => []];
                break;
        }

        $meta = isset($result['meta']) && is_array($result['meta']) ? $result['meta'] : [];

        $vulnerabilities = isset($result['vulnerabilities']) && is_array($result['vulnerabilities'])
            ? array_values($result['vulnerabilities'])
            : [];

        $vulnerabilities = $this->normalizeVulnerabilities($vulnerabilities);

        return [
            'success' => (bool) ($result['success'] ?? false),
            'message' => $result['message'] ?? esc_html__('Unknown error occurred.', 'vulntitan'),
            'vulnerabilities' => $vulnerabilities
                ? VulnerabilityRiskService::attachDecisions($normalizedItem, $vulnerabilities)
                : [],
            'meta' => $meta,
        ];
    }

    protected function normalizeVulnerabilities(array $vulnerabilities): array
    {
        $normalized = [];

        foreach ($vulnerabilities as $vuln) {
            if (!is_array($vuln)) {
                $normalized[] = $vuln;
                continue;
            }

            if (!array_key_exists('fixed_version', $vuln)) {
                $vuln['fixed_version'] = $vuln['patched_versions'] ?? null;
            }

            if (!array_key_exists('published_at', $vuln)) {
                $vuln['published_at'] = $vuln['published'] ?? null;
            }

            if (!array_key_exists('affected_versions', $vuln)) {
                $vuln['affected_versions'] = $vuln['affected'] ?? null;
            }

            if (!array_key_exists('cvss_score', $vuln)) {
                $vuln['cvss_score'] = $vuln['cvss'] ?? null;
            }

            if (!array_key_exists('cvss_vector', $vuln)) {
                $vuln['cvss_vector'] = $vuln['cvss_vector_string'] ?? null;
            }

            if (!array_key_exists('exploit_status', $vuln)) {
                $vuln['exploit_status'] = $vuln['exploit'] ?? null;
            }

            $normalized[] = $vuln;
        }

        return $normalized;
    }
}
