<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class ASA_WPVulnerability_Provider {

	const DEFAULT_API_BASE_URL = 'https://www.wpvulnerability.net/';
	const DEFAULT_DOCUMENTATION_URL = 'https://www.wpvulnerability.com/api/';

	public function scan_inventory( array $inventory, array $settings = array() ) {
		$settings   = $this->normalize_settings( $settings );
		$components = $this->build_inventory_components( $inventory );

		if ( empty( $settings['enabled'] ) ) {
			return array(
				'status'     => 'skipped',
				'error'      => '',
				'records'    => 0,
				'matches'    => 0,
				'findings'   => array(),
				'advisories' => array(),
				'details'    => __( 'WPVulnerability API matching is disabled in the Aegisify Audit SaaS settings.', 'aegisify-audit-agent' ),
				'summary'    => array(
					'reason'          => __( 'WPVulnerability API matching is disabled in the Aegisify Audit SaaS settings.', 'aegisify-audit-agent' ),
					'component_count' => count( $components ),
				),
			);
		}

		$eligibility = array();
		$targets     = $this->build_request_targets( $components, $settings, $eligibility );
		if ( empty( $targets ) ) {
			return array(
				'status'     => 'skipped',
				'error'      => '',
				'records'    => 0,
				'matches'    => 0,
				'findings'   => array(),
				'advisories' => array(),
				'details'    => __( 'No local WordPress or runtime components were eligible for WPVulnerability API matching on this agent.', 'aegisify-audit-agent' ),
				'summary'    => array(
					'reason'                    => __( 'No local WordPress or runtime components were eligible for WPVulnerability API matching on this agent.', 'aegisify-audit-agent' ),
					'component_count'           => count( $components ),
					'eligible_component_count'  => 0,
					'skipped_missing_version'   => isset( $eligibility['skipped_missing_version'] ) ? absint( $eligibility['skipped_missing_version'] ) : 0,
					'skipped_missing_slug'      => isset( $eligibility['skipped_missing_slug'] ) ? absint( $eligibility['skipped_missing_slug'] ) : 0,
					'skipped_unsupported'       => isset( $eligibility['skipped_unsupported'] ) ? absint( $eligibility['skipped_unsupported'] ) : 0,
				),
			);
		}

		$advisories           = array();
		$request_count        = 0;
		$failed_request_count = 0;
		$last_http_code       = 0;
		$error_messages       = array();
		$partial_failure      = false;
		$families             = array();
		$statistics_metadata  = array();
		$total_target_queries = count( $targets );
		$total_request_count  = $total_target_queries + 1;

		$statistics_result = $this->fetch_statistics_metadata( $settings );
		if ( ! empty( $statistics_result['attempted'] ) ) {
			$request_count++;
			if ( ! empty( $statistics_result['http_code'] ) ) {
				$last_http_code = (int) $statistics_result['http_code'];
			}
			if ( ! empty( $statistics_result['failed'] ) ) {
				$failed_request_count++;
				$partial_failure = true;
				if ( ! empty( $statistics_result['message'] ) ) {
					$error_messages[] = sanitize_text_field( (string) $statistics_result['message'] );
				}
			} elseif ( ! empty( $statistics_result['metadata'] ) && is_array( $statistics_result['metadata'] ) ) {
				$statistics_metadata = $statistics_result['metadata'];
			}
		}

		foreach ( $targets as $request_path => $target ) {
			$request_count++;
			$families[ $target['family'] ] = $target['family'];
			$response = $this->request_api( $settings, $request_path );
			if ( is_wp_error( $response ) ) {
				$failed_request_count++;
				$partial_failure  = true;
				$error_messages[] = sanitize_text_field( $response->get_error_message() );
				continue;
			}

			$last_http_code = (int) wp_remote_retrieve_response_code( $response );
			if ( 200 !== $last_http_code ) {
				$failed_request_count++;
				$partial_failure  = true;
				$error_messages[] = sprintf(
					/* translators: %d: HTTP response code from the WPVulnerability API. */
					__( 'WPVulnerability API returned HTTP %d.', 'aegisify-audit-agent' ),
					$last_http_code
				);
				continue;
			}

			$data = json_decode( (string) wp_remote_retrieve_body( $response ), true );
			if ( empty( $data ) || ! is_array( $data ) ) {
				$failed_request_count++;
				$partial_failure  = true;
				$error_messages[] = __( 'WPVulnerability API returned an empty or invalid JSON payload.', 'aegisify-audit-agent' );
				continue;
			}
			if ( ! empty( $data['error'] ) ) {
				$failed_request_count++;
				$partial_failure  = true;
				$error_messages[] = ! empty( $data['message'] ) ? sanitize_text_field( (string) $data['message'] ) : __( 'WPVulnerability API returned an error payload.', 'aegisify-audit-agent' );
				continue;
			}

			$this->append_response_advisories( $data, $target, $advisories );
		}

		$status  = empty( $advisories ) ? 'empty' : 'success';
		$message = '';
		if ( $failed_request_count > 0 && $request_count === $failed_request_count ) {
			$status  = 'remote_error';
			$message = ! empty( $error_messages ) ? implode( ' ', array_values( array_unique( array_filter( $error_messages ) ) ) ) : __( 'All WPVulnerability API requests failed for this run.', 'aegisify-audit-agent' );
		} elseif ( $failed_request_count > 0 ) {
			$message = sprintf(
				/* translators: 1: number of failed API requests, 2: total API requests. */
				__( 'WPVulnerability API completed with partial coverage: %1$d of %2$d requests failed.', 'aegisify-audit-agent' ),
				$failed_request_count,
				$request_count
			);
		}

		$summary = array(
			'reason'                    => '' !== $message ? $message : __( 'WPVulnerability API matching completed on the agent.', 'aegisify-audit-agent' ),
			'component_count'           => count( $components ),
			'supported_component_count' => $this->count_supported_components( $targets ),
			'eligible_component_count'  => isset( $eligibility['eligible_components'] ) ? absint( $eligibility['eligible_components'] ) : 0,
			'skipped_missing_version'   => isset( $eligibility['skipped_missing_version'] ) ? absint( $eligibility['skipped_missing_version'] ) : 0,
			'skipped_missing_slug'      => isset( $eligibility['skipped_missing_slug'] ) ? absint( $eligibility['skipped_missing_slug'] ) : 0,
			'skipped_unsupported'       => isset( $eligibility['skipped_unsupported'] ) ? absint( $eligibility['skipped_unsupported'] ) : 0,
			'query_count'               => count( $targets ),
			'request_count'             => $request_count,
			'failed_request_count'      => $failed_request_count,
			'http_code'                 => $last_http_code,
			'advisory_count'            => count( $advisories ),
			'families'                  => array_values( $families ),
			'documentation_url'         => $settings['documentation_url'],
			'api_base_url'              => $settings['api_base_url'],
			'supported_wordpress_endpoints' => $settings['supported_wordpress_endpoints'],
			'supported_software_endpoints'  => $settings['supported_software_endpoints'],
			'supported_additional_endpoints'=> $settings['supported_additional_endpoints'],
		);
		if ( ! empty( $statistics_metadata ) ) {
			$summary['statistics'] = $statistics_metadata;
		}
		if ( ! empty( $error_messages ) ) {
			$summary['stderr_summary'] = sanitize_text_field( implode( ' ', array_values( array_unique( array_filter( $error_messages ) ) ) ) );
		}

		$details = sprintf(
			/* translators: 1: advisory count, 2: query count, 3: API base URL */
			__( 'WPVulnerability API matched %1$d advisories across %2$d local endpoint queries using %3$s.', 'aegisify-audit-agent' ),
			count( $advisories ),
			count( $targets ),
			$settings['api_base_url']
		);
		if ( '' !== $message ) {
			$details .= ' ' . $message;
		}
		$details .= ' ' . sprintf(
			/* translators: %s: documentation URL */
			__( 'Coverage reference: %s', 'aegisify-audit-agent' ),
			$settings['documentation_url']
		);

		$findings = array();
		$findings[] = array(
			'severity' => empty( $advisories ) ? 'info' : 'medium',
			'category' => 'vulnerability',
			'title'    => __( 'WPVulnerability API local matching completed', 'aegisify-audit-agent' ),
			'details'  => $details,
		);

		return array(
			'status'     => $status,
			'error'      => '' !== $message && 'remote_error' === $status ? $message : '',
			'records'    => count( $advisories ),
			'matches'    => count( $advisories ),
			'findings'   => $findings,
			'advisories' => array_values( $advisories ),
			'details'    => $details,
			'summary'    => $summary,
		);
	}

	private function normalize_settings( array $settings ) {
		$base_url = ! empty( $settings['api_base_url'] ) ? esc_url_raw( (string) $settings['api_base_url'] ) : self::DEFAULT_API_BASE_URL;
		if ( '' === $base_url ) {
			$base_url = self::DEFAULT_API_BASE_URL;
		}
		$documentation_url = ! empty( $settings['documentation_url'] ) ? esc_url_raw( (string) $settings['documentation_url'] ) : self::DEFAULT_DOCUMENTATION_URL;
		if ( '' === $documentation_url ) {
			$documentation_url = self::DEFAULT_DOCUMENTATION_URL;
		}
		$wordpress_endpoints = ! empty( $settings['supported_wordpress_endpoints'] ) && is_array( $settings['supported_wordpress_endpoints'] ) ? array_values( array_unique( array_map( 'sanitize_key', array_map( 'strval', $settings['supported_wordpress_endpoints'] ) ) ) ) : array( 'core', 'plugin', 'theme' );
		$software_endpoints  = ! empty( $settings['supported_software_endpoints'] ) && is_array( $settings['supported_software_endpoints'] ) ? array_values( array_unique( array_map( 'sanitize_key', array_map( 'strval', $settings['supported_software_endpoints'] ) ) ) ) : array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
		$additional_endpoints = ! empty( $settings['supported_additional_endpoints'] ) && is_array( $settings['supported_additional_endpoints'] ) ? array_values( array_unique( array_map( 'sanitize_key', array_map( 'strval', $settings['supported_additional_endpoints'] ) ) ) ) : array( 'statistics', 'updates' );

		return array(
			'enabled'                       => isset( $settings['enabled'] ) ? (bool) $settings['enabled'] : true,
			'api_base_url'                  => trailingslashit( $base_url ),
			'documentation_url'             => $documentation_url,
			'supported_wordpress_endpoints' => $wordpress_endpoints,
			'supported_software_endpoints'  => $software_endpoints,
			'supported_additional_endpoints'=> $additional_endpoints,
		);
	}

	private function build_inventory_components( array $inventory ) {
		$components = array();

		$core_version = ! empty( $inventory['wordpress_core']['version'] ) ? $this->normalize_component_version( (string) $inventory['wordpress_core']['version'] ) : '';
		if ( '' !== $core_version ) {
			$components[] = array(
				'component_type' => 'wordpress_core',
				'ecosystem'      => 'wordpress',
				'slug'           => 'wordpress',
				'name'           => 'WordPress Core',
				'version'        => $core_version,
				'active'         => true,
			);
		}

		$this->append_wordpress_component_list( $components, ! empty( $inventory['plugins']['active'] ) && is_array( $inventory['plugins']['active'] ) ? $inventory['plugins']['active'] : array(), 'plugin' );
		$this->append_wordpress_component_list( $components, ! empty( $inventory['plugins']['inactive'] ) && is_array( $inventory['plugins']['inactive'] ) ? $inventory['plugins']['inactive'] : array(), 'plugin' );
		$this->append_wordpress_component_list( $components, ! empty( $inventory['themes']['active'] ) && is_array( $inventory['themes']['active'] ) ? $inventory['themes']['active'] : array(), 'theme' );
		$this->append_wordpress_component_list( $components, ! empty( $inventory['themes']['inactive'] ) && is_array( $inventory['themes']['inactive'] ) ? $inventory['themes']['inactive'] : array(), 'theme' );
		$this->append_wordpress_component_list( $components, ! empty( $inventory['mu_plugins'] ) && is_array( $inventory['mu_plugins'] ) ? $inventory['mu_plugins'] : array(), 'mu_plugin' );
		$this->append_runtime_components( $components, ! empty( $inventory['runtime'] ) && is_array( $inventory['runtime'] ) ? $inventory['runtime'] : array() );

		return array_values( $components );
	}

	private function append_wordpress_component_list( array &$components, array $items, $component_type ) {
		foreach ( $items as $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}
			$slug    = ! empty( $item['slug'] ) ? sanitize_title( (string) $item['slug'] ) : '';
			$version = ! empty( $item['version'] ) ? $this->normalize_component_version( (string) $item['version'] ) : '';
			if ( '' === $slug || '' === $version ) {
				continue;
			}
			$components[] = array(
				'component_type' => sanitize_key( (string) $component_type ),
				'ecosystem'      => 'wordpress',
				'slug'           => $slug,
				'name'           => ! empty( $item['name'] ) ? sanitize_text_field( (string) $item['name'] ) : $slug,
				'version'        => $version,
				'active'         => ! empty( $item['active'] ),
			);
		}
	}

	private function append_runtime_components( array &$components, array $runtime ) {
		$runtime_map = array(
			array( 'component_type' => 'php_runtime', 'ecosystem' => 'php', 'slug' => 'php', 'name' => 'PHP Runtime', 'version_key' => 'php_version' ),
			array( 'component_type' => 'curl_runtime', 'ecosystem' => 'curl', 'slug' => 'curl', 'name' => 'cURL Runtime', 'version_key' => 'curl_version' ),
			array( 'component_type' => 'imagemagick_runtime', 'ecosystem' => 'imagemagick', 'slug' => 'imagemagick', 'name' => 'ImageMagick Runtime', 'version_key' => 'imagemagick_version' ),
			array( 'component_type' => 'sqlite_runtime', 'ecosystem' => 'sqlite', 'slug' => 'sqlite', 'name' => 'SQLite Runtime', 'version_key' => 'sqlite_version' ),
			array( 'component_type' => 'memcached_runtime', 'ecosystem' => 'memcached', 'slug' => 'memcached', 'name' => 'Memcached Runtime', 'version_key' => 'memcached_version' ),
			array( 'component_type' => 'redis_runtime', 'ecosystem' => 'redis', 'slug' => 'redis', 'name' => 'Redis Runtime', 'version_key' => 'redis_version' ),
		);
		foreach ( $runtime_map as $config ) {
			$version = ! empty( $runtime[ $config['version_key'] ] ) ? $this->normalize_component_version( (string) $runtime[ $config['version_key'] ] ) : '';
			if ( '' === $version ) {
				continue;
			}
			$components[] = array(
				'component_type' => $config['component_type'],
				'ecosystem'      => $config['ecosystem'],
				'slug'           => $config['slug'],
				'name'           => $config['name'],
				'version'        => $version,
				'active'         => true,
			);
		}

		$server = ! empty( $runtime['server_software'] ) ? (string) $runtime['server_software'] : '';
		if ( preg_match( '/Apache\/([0-9][0-9A-Za-z\.\-_]+)/i', $server, $matches ) ) {
			$components[] = array(
				'component_type' => 'apache_runtime',
				'ecosystem'      => 'apache',
				'slug'           => 'apache',
				'name'           => 'Apache Runtime',
				'version'        => $this->normalize_component_version( (string) $matches[1] ),
				'active'         => true,
			);
		} elseif ( preg_match( '/nginx\/([0-9][0-9A-Za-z\.\-_]+)/i', $server, $matches ) ) {
			$components[] = array(
				'component_type' => 'nginx_runtime',
				'ecosystem'      => 'nginx',
				'slug'           => 'nginx',
				'name'           => 'Nginx Runtime',
				'version'        => $this->normalize_component_version( (string) $matches[1] ),
				'active'         => true,
			);
		}

		$db_version = ! empty( $runtime['db_version'] ) ? $this->normalize_component_version( (string) $runtime['db_version'] ) : '';
		$db_engine  = ! empty( $runtime['db_engine'] ) ? sanitize_key( strtolower( (string) $runtime['db_engine'] ) ) : '';
		if ( '' !== $db_version && 'mariadb' === $db_engine ) {
			$components[] = array(
				'component_type' => 'mariadb_runtime',
				'ecosystem'      => 'mariadb',
				'slug'           => 'mariadb',
				'name'           => 'MariaDB Runtime',
				'version'        => $db_version,
				'active'         => true,
			);
		} elseif ( '' !== $db_version && 'mysql' === $db_engine ) {
			$components[] = array(
				'component_type' => 'mysql_runtime',
				'ecosystem'      => 'mysql',
				'slug'           => 'mysql',
				'name'           => 'MySQL Runtime',
				'version'        => $db_version,
				'active'         => true,
			);
		}
	}

	private function build_request_targets( array $components, array $settings, array &$eligibility = array() ) {
		$targets = array();
		$eligibility = array(
			'eligible_components'     => 0,
			'skipped_missing_version' => 0,
			'skipped_missing_slug'    => 0,
			'skipped_unsupported'     => 0,
		);
		foreach ( $components as $component ) {
			if ( ! is_array( $component ) ) {
				continue;
			}
			$target = $this->map_component_to_target( $component, $settings, $eligibility );
			if ( empty( $target['path'] ) || empty( $target['family'] ) ) {
				continue;
			}
			$eligibility['eligible_components']++;
			$key = (string) $target['path'];
			if ( empty( $targets[ $key ] ) ) {
				$targets[ $key ] = array(
					'path'       => $target['path'],
					'family'     => $target['family'],
					'api_type'   => $target['api_type'],
					'query_key'  => $target['query_key'],
					'components' => array(),
				);
			}
			$targets[ $key ]['components'][] = $target['component'];
		}
		return $targets;
	}

	private function map_component_to_target( array $component, array $settings, array &$eligibility = array() ) {
		$component_type = ! empty( $component['component_type'] ) ? sanitize_key( (string) $component['component_type'] ) : '';
		$ecosystem      = ! empty( $component['ecosystem'] ) ? sanitize_key( (string) $component['ecosystem'] ) : '';
		$slug           = ! empty( $component['slug'] ) ? sanitize_text_field( (string) $component['slug'] ) : '';
		$version        = $this->normalize_component_version( ! empty( $component['version'] ) ? (string) $component['version'] : '' );

		if ( 'wordpress_core' === $component_type ) {
			if ( ! in_array( 'core', $settings['supported_wordpress_endpoints'], true ) ) {
				$eligibility['skipped_unsupported']++;
				return array();
			}
			if ( '' === $version ) {
				$eligibility['skipped_missing_version']++;
				return array();
			}
			return array(
				'path'      => 'core/' . rawurlencode( $version ) . '/',
				'family'    => 'wordpress',
				'api_type'  => 'core',
				'query_key' => $version,
				'component' => $component,
			);
		}

		if ( in_array( $component_type, array( 'plugin', 'mu_plugin' ), true ) ) {
			if ( ! in_array( 'plugin', $settings['supported_wordpress_endpoints'], true ) ) {
				$eligibility['skipped_unsupported']++;
				return array();
			}
			if ( '' === $slug ) {
				$eligibility['skipped_missing_slug']++;
				return array();
			}
			if ( '' === $version ) {
				$eligibility['skipped_missing_version']++;
				return array();
			}
			return array(
				'path'      => 'plugin/' . rawurlencode( $slug ) . '/',
				'family'    => 'wordpress',
				'api_type'  => 'plugin',
				'query_key' => $slug,
				'component' => $component,
			);
		}

		if ( 'theme' === $component_type ) {
			if ( ! in_array( 'theme', $settings['supported_wordpress_endpoints'], true ) ) {
				$eligibility['skipped_unsupported']++;
				return array();
			}
			if ( '' === $slug ) {
				$eligibility['skipped_missing_slug']++;
				return array();
			}
			if ( '' === $version ) {
				$eligibility['skipped_missing_version']++;
				return array();
			}
			return array(
				'path'      => 'theme/' . rawurlencode( $slug ) . '/',
				'family'    => 'wordpress',
				'api_type'  => 'theme',
				'query_key' => $slug,
				'component' => $component,
			);
		}

		if ( '' === $version ) {
			$eligibility['skipped_missing_version']++;
			return array();
		}

		$software_map = array(
			'php'         => 'php',
			'apache'      => 'apache',
			'nginx'       => 'nginx',
			'mariadb'     => 'mariadb',
			'mysql'       => 'mysql',
			'imagemagick' => 'imagemagick',
			'curl'        => 'curl',
			'memcached'   => 'memcached',
			'redis'       => 'redis',
			'sqlite'      => 'sqlite',
		);
		if ( ! empty( $software_map[ $ecosystem ] ) ) {
			if ( ! in_array( $software_map[ $ecosystem ], $settings['supported_software_endpoints'], true ) ) {
				$eligibility['skipped_unsupported']++;
				return array();
			}
			$query_version = $this->software_query_version( $version );
			if ( '' === $query_version ) {
				$eligibility['skipped_missing_version']++;
				return array();
			}
			return array(
				'path'      => $software_map[ $ecosystem ] . '/' . rawurlencode( $query_version ) . '/',
				'family'    => 'software',
				'api_type'  => $software_map[ $ecosystem ],
				'query_key' => $query_version,
				'component' => $component,
			);
		}

		$eligibility['skipped_unsupported']++;
		return array();
	}

	private function append_response_advisories( array $payload, array $target, array &$advisories ) {
		$data            = ! empty( $payload['data'] ) && is_array( $payload['data'] ) ? $payload['data'] : array();
		$vulnerabilities = ! empty( $data['vulnerability'] ) && is_array( $data['vulnerability'] ) ? $data['vulnerability'] : array();
		$api_updated_at  = ! empty( $payload['updated'] ) ? $this->normalize_timestamp( $payload['updated'] ) : '';
		$components      = ! empty( $target['components'] ) && is_array( $target['components'] ) ? $target['components'] : array();
		$api_link        = ! empty( $data['link'] ) ? esc_url_raw( (string) $data['link'] ) : '';

		foreach ( $vulnerabilities as $entry ) {
			if ( ! is_array( $entry ) ) {
				continue;
			}

			$source_meta    = $this->extract_source_metadata( ! empty( $entry['source'] ) && is_array( $entry['source'] ) ? $entry['source'] : array() );
			$cvss           = $this->extract_cvss_data( ! empty( $entry['impact'] ) ? $entry['impact'] : array() );
			$operator       = ! empty( $entry['operator'] ) && is_array( $entry['operator'] ) ? $entry['operator'] : array();
			$fixed_versions = $this->derive_fixed_versions( $operator );
			$references     = $source_meta['references'];
			if ( '' !== $api_link ) {
				$references[] = $api_link;
			}

			foreach ( $components as $component ) {
				$component_version = $this->normalize_component_version( ! empty( $component['version'] ) ? (string) $component['version'] : '' );
				if ( ! $this->entry_matches_component( $target['api_type'], $component_version, $operator ) ) {
					continue;
				}

				$record_id = ! empty( $entry['uuid'] ) ? sanitize_text_field( (string) $entry['uuid'] ) : md5( wp_json_encode( $entry ) . '|' . $target['path'] . '|' . $component_version );
				$advisory_key = sanitize_key( $record_id . '-' . sanitize_key( (string) ( ! empty( $component['component_type'] ) ? $component['component_type'] : 'component' ) ) . '-' . sanitize_title( (string) ( ! empty( $component['slug'] ) ? $component['slug'] : '' ) ) . '-' . md5( $component_version ) );
				$advisories[ $advisory_key ] = array(
					'provider_record_id' => $record_id,
					'cve_id'             => $this->extract_cve_from_aliases( $source_meta['aliases'] ),
					'title'              => ! empty( $entry['name'] ) ? sanitize_text_field( (string) $entry['name'] ) : $record_id,
					'description'        => ! empty( $entry['description'] ) ? wp_kses_post( (string) $entry['description'] ) : '',
					'severity_label'     => $this->normalize_severity_label( ! empty( $cvss['severity'] ) ? $cvss['severity'] : '' ),
					'cvss_version'       => ! empty( $cvss['version'] ) ? sanitize_text_field( (string) $cvss['version'] ) : '',
					'cvss_score'         => isset( $cvss['score'] ) ? (float) $cvss['score'] : 0,
					'affected_versions'  => ! empty( $operator ) ? array( $operator ) : array(),
					'fixed_versions'     => $fixed_versions,
					'references'         => array_values( array_unique( array_filter( $references ) ) ),
					'aliases'            => $source_meta['aliases'],
					'published_at'       => $source_meta['published_at'],
					'updated_provider_at'=> $api_updated_at,
					'component_type'     => ! empty( $component['component_type'] ) ? sanitize_key( (string) $component['component_type'] ) : '',
					'slug'               => ! empty( $component['slug'] ) ? sanitize_title( (string) $component['slug'] ) : '',
					'name'               => ! empty( $component['name'] ) ? sanitize_text_field( (string) $component['name'] ) : '',
					'installed_version'  => $component_version,
					'api_type'           => ! empty( $target['api_type'] ) ? sanitize_key( (string) $target['api_type'] ) : '',
					'api_family'         => ! empty( $target['family'] ) ? sanitize_key( (string) $target['family'] ) : '',
					'raw'                => array(
						'payload'      => $entry,
						'query_key'    => ! empty( $target['query_key'] ) ? sanitize_text_field( (string) $target['query_key'] ) : '',
						'request_path' => ! empty( $target['path'] ) ? sanitize_text_field( (string) $target['path'] ) : '',
					),
				);
			}
		}
	}

	private function request_api( array $settings, $request_path ) {
		$url = trailingslashit( (string) $settings['api_base_url'] ) . ltrim( (string) $request_path, '/' );
		return wp_safe_remote_get(
			esc_url_raw( $url ),
			array(
				'timeout'   => 20,
				'sslverify' => true,
				'headers'   => array(
					'Accept' => 'application/json',
				),
			)
		);
	}

	private function fetch_statistics_metadata( array $settings ) {
		$result = array(
			'attempted' => in_array( 'statistics', $settings['supported_additional_endpoints'], true ),
			'failed'    => false,
			'http_code' => 0,
			'message'   => '',
			'metadata'  => array(),
		);

		if ( empty( $result['attempted'] ) ) {
			return $result;
		}

		$response = $this->request_api( $settings, '' );
		if ( is_wp_error( $response ) ) {
			$result['failed']  = true;
			$result['message'] = sanitize_text_field( $response->get_error_message() );
			return $result;
		}

		$result['http_code'] = (int) wp_remote_retrieve_response_code( $response );
		if ( 200 !== $result['http_code'] ) {
			$result['failed']  = true;
			$result['message'] = sprintf(
				/* translators: %d: HTTP response code from the WPVulnerability statistics endpoint. */
				__( 'WPVulnerability statistics endpoint returned HTTP %d.', 'aegisify-audit-agent' ),
				$result['http_code']
			);
			return $result;
		}

		$data = json_decode( (string) wp_remote_retrieve_body( $response ), true );
		if ( empty( $data ) || ! is_array( $data ) ) {
			$result['failed']  = true;
			$result['message'] = __( 'WPVulnerability statistics endpoint returned an empty or invalid JSON payload.', 'aegisify-audit-agent' );
			return $result;
		}
		if ( ! empty( $data['error'] ) ) {
			$result['failed']  = true;
			$result['message'] = ! empty( $data['message'] ) ? sanitize_text_field( (string) $data['message'] ) : __( 'WPVulnerability statistics endpoint returned an error payload.', 'aegisify-audit-agent' );
			return $result;
		}

		$stats = ! empty( $data['stats'] ) && is_array( $data['stats'] ) ? $data['stats'] : array();
		$result['metadata'] = array(
			'updated_at' => ! empty( $data['updated'] ) ? $this->normalize_timestamp( $data['updated'] ) : '',
			'products'   => array(
				'core'    => isset( $stats['products']['core'] ) ? absint( $stats['products']['core'] ) : 0,
				'plugins' => isset( $stats['products']['plugins'] ) ? absint( $stats['products']['plugins'] ) : 0,
				'themes'  => isset( $stats['products']['themes'] ) ? absint( $stats['products']['themes'] ) : 0,
			),
			'coverage'   => array(
				'core'        => isset( $stats['core'] ) ? absint( $stats['core'] ) : 0,
				'plugins'     => isset( $stats['plugins'] ) ? absint( $stats['plugins'] ) : 0,
				'themes'      => isset( $stats['themes'] ) ? absint( $stats['themes'] ) : 0,
				'php'         => isset( $stats['php'] ) ? absint( $stats['php'] ) : 0,
				'apache'      => isset( $stats['apache'] ) ? absint( $stats['apache'] ) : 0,
				'nginx'       => isset( $stats['nginx'] ) ? absint( $stats['nginx'] ) : 0,
				'mariadb'     => isset( $stats['mariadb'] ) ? absint( $stats['mariadb'] ) : 0,
				'mysql'       => isset( $stats['mysql'] ) ? absint( $stats['mysql'] ) : 0,
				'imagemagick' => isset( $stats['imagemagick'] ) ? absint( $stats['imagemagick'] ) : 0,
				'curl'        => isset( $stats['curl'] ) ? absint( $stats['curl'] ) : 0,
				'memcached'   => isset( $stats['memcached'] ) ? absint( $stats['memcached'] ) : 0,
				'redis'       => isset( $stats['redis'] ) ? absint( $stats['redis'] ) : 0,
				'sqlite'      => isset( $stats['sqlite'] ) ? absint( $stats['sqlite'] ) : 0,
			),
		);

		return $result;
	}

	private function normalize_component_version( $version ) {
		$version = sanitize_text_field( trim( (string) $version ) );
		$version = preg_replace( '/[\-_]?mariadb$/i', '', $version );
		$version = preg_replace( '/[\-_]?mysql$/i', '', $version );
		return sanitize_text_field( trim( (string) $version ) );
	}

	private function software_query_version( $version ) {
		$version = $this->normalize_component_version( $version );
		if ( '' === $version ) {
			return '';
		}
		if ( preg_match( '/^\d+\.\d+/', $version, $matches ) ) {
			return sanitize_text_field( (string) $matches[0] );
		}
		if ( preg_match( '/^\d+/', $version, $matches ) ) {
			return sanitize_text_field( (string) $matches[0] );
		}
		return $version;
	}

	private function entry_matches_component( $api_type, $component_version, array $operator ) {
		if ( 'core' === $api_type ) {
			return '' !== $component_version;
		}
		if ( empty( $operator ) ) {
			return '' !== $component_version;
		}
		return $this->version_matches_operator( $component_version, $operator );
	}

	private function version_matches_operator( $component_version, array $operator ) {
		$component_version = $this->normalize_component_version( $component_version );
		if ( '' === $component_version ) {
			return false;
		}

		$comparisons = array(
			array(
				'version'  => ! empty( $operator['min_version'] ) ? $this->normalize_component_version( (string) $operator['min_version'] ) : '',
				'operator' => ! empty( $operator['min_operator'] ) ? strtolower( sanitize_text_field( (string) $operator['min_operator'] ) ) : '',
			),
			array(
				'version'  => ! empty( $operator['max_version'] ) ? $this->normalize_component_version( (string) $operator['max_version'] ) : '',
				'operator' => ! empty( $operator['max_operator'] ) ? strtolower( sanitize_text_field( (string) $operator['max_operator'] ) ) : '',
			),
		);

		$has_comparison = false;
		foreach ( $comparisons as $comparison ) {
			if ( '' === $comparison['version'] || '' === $comparison['operator'] ) {
				continue;
			}
			$has_comparison = true;
			if ( ! in_array( $comparison['operator'], array( 'lt', 'le', 'eq', 'ne', 'gt', 'ge', '<', '<=', '=', '!=', '<>', '>', '>=' ), true ) ) {
				continue;
			}
			if ( ! version_compare( $component_version, $comparison['version'], $comparison['operator'] ) ) {
				return false;
			}
		}

		return $has_comparison;
	}

	private function derive_fixed_versions( array $operator ) {
		if ( empty( $operator ) || ! empty( $operator['unfixed'] ) ) {
			return array();
		}
		$max_version  = ! empty( $operator['max_version'] ) ? $this->normalize_component_version( (string) $operator['max_version'] ) : '';
		$max_operator = ! empty( $operator['max_operator'] ) ? strtolower( sanitize_text_field( (string) $operator['max_operator'] ) ) : '';
		if ( '' !== $max_version && in_array( $max_operator, array( 'lt', '<' ), true ) ) {
			return array( $max_version );
		}
		return array();
	}

	private function extract_source_metadata( array $sources ) {
		$aliases     = array();
		$references  = array();
		$published   = '';
		foreach ( $sources as $source ) {
			if ( ! is_array( $source ) ) {
				continue;
			}
			if ( ! empty( $source['id'] ) ) {
				$aliases[] = strtoupper( sanitize_text_field( (string) $source['id'] ) );
			}
			if ( ! empty( $source['link'] ) ) {
				$references[] = esc_url_raw( (string) $source['link'] );
			}
			if ( '' === $published && ! empty( $source['date'] ) ) {
				$published = sanitize_text_field( (string) $source['date'] );
			}
		}
		return array(
			'aliases'      => array_values( array_unique( array_filter( $aliases ) ) ),
			'references'   => array_values( array_unique( array_filter( $references ) ) ),
			'published_at' => $published,
		);
	}

	private function extract_cve_from_aliases( array $aliases ) {
		foreach ( $aliases as $alias ) {
			$alias = strtoupper( sanitize_text_field( (string) $alias ) );
			if ( preg_match( '/^CVE-\d{4}-\d{4,}$/', $alias ) ) {
				return $alias;
			}
		}
		return '';
	}

	private function extract_cvss_data( $impact ) {
		$impact = is_array( $impact ) ? $impact : array();
		if ( isset( $impact['cvss'] ) && is_array( $impact['cvss'] ) ) {
			return $impact['cvss'];
		}
		if ( isset( $impact[0] ) && is_array( $impact[0] ) && isset( $impact[0]['cvss'] ) && is_array( $impact[0]['cvss'] ) ) {
			return $impact[0]['cvss'];
		}
		return array();
	}

	private function normalize_severity_label( $severity ) {
		$severity = strtolower( sanitize_text_field( (string) $severity ) );
		$map = array(
			'c'        => 'critical',
			'critical' => 'critical',
			'h'        => 'high',
			'high'     => 'high',
			'm'        => 'medium',
			'medium'   => 'medium',
			'l'        => 'low',
			'low'      => 'low',
			'i'        => 'info',
			'info'     => 'info',
		);
		return ! empty( $map[ $severity ] ) ? $map[ $severity ] : '';
	}

	private function normalize_timestamp( $value ) {
		if ( is_numeric( $value ) ) {
			return gmdate( 'Y-m-d H:i:s', (int) $value );
		}
		$value = trim( (string) $value );
		if ( '' === $value ) {
			return '';
		}
		$timestamp = strtotime( $value );
		return false === $timestamp ? '' : gmdate( 'Y-m-d H:i:s', $timestamp );
	}

	private function count_supported_components( array $targets ) {
		$count = 0;
		foreach ( $targets as $target ) {
			$count += ! empty( $target['components'] ) && is_array( $target['components'] ) ? count( $target['components'] ) : 0;
		}
		return $count;
	}
}
