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

class ASA_Vulnerability_Scan {

	public function build_payload( $scan_profile = '' ) {
		$scan_profile = sanitize_key( (string) $scan_profile );
		$started_at   = microtime( true );
		$started_gmt  = gmdate( 'Y-m-d H:i:s' );
		$inventory_blob = ASA_Local_Inventory::generate();
		$inventory      = ! empty( $inventory_blob['inventory'] ) && is_array( $inventory_blob['inventory'] ) ? $inventory_blob['inventory'] : array();
		$summary        = ! empty( $inventory_blob['summary'] ) && is_array( $inventory_blob['summary'] ) ? $inventory_blob['summary'] : array();
		$privacy        = ! empty( $inventory_blob['privacy'] ) && is_array( $inventory_blob['privacy'] ) ? $inventory_blob['privacy'] : array();
		$tooling        = ! empty( $inventory['tooling_capabilities'] ) && is_array( $inventory['tooling_capabilities'] ) ? $inventory['tooling_capabilities'] : ASA_Local_Inventory::get_tooling_capabilities();
		$audits         = ! empty( $inventory['dependency_audits'] ) && is_array( $inventory['dependency_audits'] ) ? $inventory['dependency_audits'] : array();
		$connection_status = class_exists( 'ASA_Auth' ) && is_callable( array( 'ASA_Auth', 'refresh_connection_status' ) )
			? ASA_Auth::refresh_connection_status()
			: ASA_Auth::get_connection_status();
		$remote_provider_settings = ! empty( $connection_status['provider_settings'] ) && is_array( $connection_status['provider_settings'] ) ? $connection_status['provider_settings'] : array();
		$wpvulnerability_settings = ! empty( $remote_provider_settings['wpvulnerability'] ) && is_array( $remote_provider_settings['wpvulnerability'] ) ? $remote_provider_settings['wpvulnerability'] : array();

		$plugin_count = (int) ( count( (array) ( ! empty( $inventory['plugins']['active'] ) ? $inventory['plugins']['active'] : array() ) ) + count( (array) ( ! empty( $inventory['plugins']['inactive'] ) ? $inventory['plugins']['inactive'] : array() ) ) + count( (array) ( ! empty( $inventory['mu_plugins'] ) ? $inventory['mu_plugins'] : array() ) ) );
		$theme_count  = (int) ( count( (array) ( ! empty( $inventory['themes']['active'] ) ? $inventory['themes']['active'] : array() ) ) + count( (array) ( ! empty( $inventory['themes']['inactive'] ) ? $inventory['themes']['inactive'] : array() ) ) );
		$core_version = ! empty( $inventory['wordpress_core']['version'] ) ? sanitize_text_field( (string) $inventory['wordpress_core']['version'] ) : __( 'unknown', 'aegisify-audit-agent' );

		$provider_status = array();
		$results         = array();
		$flattened_advisories = array();
		$local_wordpress_results    = array();
		$local_wordpress_findings   = array();
		$local_wordpress_advisories = array();
		$local_wordpress_summary    = array();
		$wpvulnerability_summary    = array();
		$advisory_total  = 0;
		$executed_total  = 0;
		$error_total     = 0;
		$finding_total   = 0;

		$results[] = array(
			'severity' => 'info',
			'category' => 'vulnerability',
			'title'    => __( 'Agent local software vulnerability scan executed', 'aegisify-audit-agent' ),
			'details'  => sprintf(
				/* translators: 1: core version, 2: plugin count, 3: theme count, 4: composer count, 5: python count, 6: js count */
				__( 'The agent completed a local software inventory for WordPress core %1$s with %2$d plugins, %3$d themes, %4$d Composer packages, %5$d Python packages, and %6$d JavaScript packages before dependency-advisory enrichment.', 'aegisify-audit-agent' ),
				$core_version,
				$plugin_count,
				$theme_count,
				(int) count( (array) ( ! empty( $inventory['composer_packages'] ) ? $inventory['composer_packages'] : array() ) ),
				(int) count( (array) ( ! empty( $inventory['python_packages'] ) ? $inventory['python_packages'] : array() ) ),
				(int) count( (array) ( ! empty( $inventory['js_packages'] ) ? $inventory['js_packages'] : array() ) )
			),
		);

		$local_wordpress_results = array(
			array(
				'severity' => 'info',
				'category' => 'vulnerability',
				'title'    => __( 'Agent local WordPress component inventory collected', 'aegisify-audit-agent' ),
				'details'  => __( 'The agent collected local WordPress core, plugin, theme, Composer, Python, and JavaScript inventory for SaaS-side OSV correlation and package-manager audit enrichment. No separate WordPress-only third-party feed or CLI dependency is required for this route.', 'aegisify-audit-agent' ),
			)
		);
		$local_wordpress_findings = $this->build_local_wordpress_risk_findings( $inventory );
		$local_wordpress_advisories = array();
		$local_wordpress_summary = array(
			'status' => 'inventory_collected',
			'provider' => 'agent_inventory',
			'core_version' => $core_version,
			'plugin_count' => $plugin_count,
			'theme_count' => $theme_count,
			'local_risk_count' => count( $local_wordpress_findings ),
		);

		$wpvulnerability_scan = array(
			'status'     => 'unavailable',
			'error'      => __( 'WPVulnerability provider class is unavailable on the agent.', 'aegisify-audit-agent' ),
			'records'    => 0,
			'matches'    => 0,
			'findings'   => array(),
			'advisories' => array(),
			'details'    => __( 'WPVulnerability provider class is unavailable on the agent.', 'aegisify-audit-agent' ),
			'summary'    => array(),
		);
		if ( class_exists( 'ASA_WPVulnerability_Provider' ) ) {
			try {
				$wpvulnerability_scan = ( new ASA_WPVulnerability_Provider() )->scan_inventory( $inventory, $wpvulnerability_settings );
			} catch ( Throwable $throwable ) {
				if ( class_exists( 'ASA_Logger' ) ) {
					ASA_Logger::log(
						'scan',
						'error',
						'vulnerability',
						'build_payload',
						__( 'The agent WPVulnerability provider failed with a runtime exception and was skipped so the vulnerability route could finish.', 'aegisify-audit-agent' ),
						array( 'message' => sanitize_text_field( $throwable->getMessage() ) ),
						10
					);
				}
				$wpvulnerability_scan = array(
					'status'     => 'error',
					'error'      => sanitize_text_field( $throwable->getMessage() ),
					'records'    => 0,
					'matches'    => 0,
					'findings'   => array(),
					'advisories' => array(),
					'details'    => __( 'WPVulnerability provider failed on the agent and was skipped so the remaining vulnerability payload could complete.', 'aegisify-audit-agent' ),
					'summary'    => array(
						'engine' => 'wpvulnerability_api',
						'status' => 'error',
						'reason' => sanitize_text_field( $throwable->getMessage() ),
					),
				);
			}
		}
		$wpvulnerability_summary = ! empty( $wpvulnerability_scan['summary'] ) && is_array( $wpvulnerability_scan['summary'] ) ? $wpvulnerability_scan['summary'] : array();
		if ( ! empty( $wpvulnerability_scan['findings'] ) && is_array( $wpvulnerability_scan['findings'] ) ) {
			$local_wordpress_results = array_merge( $local_wordpress_results, $wpvulnerability_scan['findings'] );
		}
		if ( ! empty( $wpvulnerability_scan['advisories'] ) && is_array( $wpvulnerability_scan['advisories'] ) ) {
			$local_wordpress_advisories = array_merge( $local_wordpress_advisories, array_values( $wpvulnerability_scan['advisories'] ) );
			$advisory_total += count( $wpvulnerability_scan['advisories'] );
			$finding_total  += count( $wpvulnerability_scan['advisories'] );
		}
		if ( in_array( $wpvulnerability_scan['status'], array( 'success', 'empty', 'remote_error' ), true ) ) {
			$executed_total++;
		}
		if ( in_array( $wpvulnerability_scan['status'], array( 'remote_error', 'unavailable' ), true ) ) {
			$error_total++;
		}
		$provider_status['wpvulnerability_api'] = array(
			'status'    => ! empty( $wpvulnerability_scan['status'] ) ? sanitize_key( (string) $wpvulnerability_scan['status'] ) : 'skipped',
			'records'   => ! empty( $wpvulnerability_scan['records'] ) ? absint( $wpvulnerability_scan['records'] ) : 0,
			'matches'   => ! empty( $wpvulnerability_scan['matches'] ) ? absint( $wpvulnerability_scan['matches'] ) : 0,
			'error'     => ! empty( $wpvulnerability_scan['error'] ) ? sanitize_text_field( (string) $wpvulnerability_scan['error'] ) : '',
			'details'   => ! empty( $wpvulnerability_scan['details'] ) ? sanitize_text_field( (string) $wpvulnerability_scan['details'] ) : '',
			'source'    => 'remote',
			'execution' => $wpvulnerability_summary,
		);

		if ( ! empty( $local_wordpress_findings ) ) {
			$local_wordpress_results[] = array(
				'severity' => 'medium',
				'category' => 'vulnerability',
				'title'    => __( 'Agent local WordPress component risk signals detected', 'aegisify-audit-agent' ),
				'details'  => sprintf(
					/* translators: %d: number of local WordPress component risk signals */
					__( 'The agent identified %d local WordPress component risk signals from version/update state, inactive component exposure, and automatic-update posture.', 'aegisify-audit-agent' ),
					count( $local_wordpress_findings )
				),
			);
		}

		$audit_provider_map = array(
			'composer' => 'composer_audit',
			'pip'      => 'pip_audit',
			'npm'      => 'npm_audit',
			'yarn'     => 'yarn_audit',
			'pnpm'     => 'pnpm_audit',
		);

		foreach ( $audit_provider_map as $audit_key => $provider_key ) {
			$audit      = ! empty( $audits[ $audit_key ] ) && is_array( $audits[ $audit_key ] ) ? $audits[ $audit_key ] : array();
			$status     = ! empty( $audit['status'] ) ? sanitize_key( (string) $audit['status'] ) : 'not_applicable';
			$records    = ! empty( $audit['records'] ) && is_array( $audit['records'] ) ? $audit['records'] : array();
			$execution  = ! empty( $audit['execution'] ) && is_array( $audit['execution'] ) ? $audit['execution'] : array();
			$record_cnt = count( $records );
			$error      = ! empty( $audit['error'] ) ? sanitize_text_field( (string) $audit['error'] ) : '';
			$details    = $this->build_provider_details( $audit_key, $status, $record_cnt, $execution, $error );
			$provider_status[ $provider_key ] = array(
				'status'    => $status,
				'records'   => $record_cnt,
				'matches'   => $record_cnt,
				'error'     => $error,
				'details'   => $details,
				'source'    => 'agent',
				'execution' => $execution,
			);

			if ( in_array( $status, array( 'success', 'empty', 'error', 'unavailable' ), true ) ) {
				$executed_total++;
			}
			if ( in_array( $status, array( 'error', 'unavailable' ), true ) ) {
				$error_total++;
			}
			$advisory_total += $record_cnt;
			$finding_total  += $record_cnt;
			foreach ( $records as $record ) {
				if ( is_array( $record ) ) {
					$flattened_advisories[] = $record;
				}
			}

			$result_severity = 'info';
			if ( $record_cnt > 0 ) {
				$result_severity = 'medium';
			} elseif ( in_array( $status, array( 'error', 'unavailable' ), true ) ) {
				$result_severity = 'medium';
			}
			$results[] = array(
				'severity' => $result_severity,
				'category' => 'vulnerability',
				'title'    => sprintf(
					/* translators: %s: dependency audit key */
					__( 'Agent %s dependency audit status', 'aegisify-audit-agent' ),
					$audit_key
				),
				'details'  => $details,
			);
		}

		$local_risk_total = count( $local_wordpress_findings );
		$local_status = ( $advisory_total + $local_risk_total ) > 0 ? 'success' : ( $executed_total > 0 ? 'executed' : 'inventory_only' );
		$local_details = sprintf(
			/* translators: 1: core version, 2: plugin count, 3: theme count, 4: advisory count, 5: WordPress risk signal count */
			__( 'Agent completed the local software vulnerability route for WordPress core %1$s with %2$d plugins and %3$d themes. Total dependency/package-manager advisory records: %4$d. Local WordPress component risk signals: %5$d.', 'aegisify-audit-agent' ),
			$core_version,
			$plugin_count,
			$theme_count,
			$advisory_total,
			$local_risk_total
		);
		$local_details .= ' ' . sprintf(
			/* translators: 1: local inventory status, 2: composer advisories, 3: pip advisories, 4: npm advisories, 5: yarn advisories, 6: pnpm advisories */
			__( 'Local inventory status: %1$s. Composer advisories: %2$d. pip advisories: %3$d. npm advisories: %4$d. Yarn advisories: %5$d. pnpm advisories: %6$d.', 'aegisify-audit-agent' ),
			! empty( $local_wordpress_summary['status'] ) ? sanitize_text_field( (string) $local_wordpress_summary['status'] ) : __( 'unknown', 'aegisify-audit-agent' ),
			! empty( $provider_status['composer_audit']['records'] ) ? (int) $provider_status['composer_audit']['records'] : 0,
			! empty( $provider_status['pip_audit']['records'] ) ? (int) $provider_status['pip_audit']['records'] : 0,
			! empty( $provider_status['npm_audit']['records'] ) ? (int) $provider_status['npm_audit']['records'] : 0,
			! empty( $provider_status['yarn_audit']['records'] ) ? (int) $provider_status['yarn_audit']['records'] : 0,
			! empty( $provider_status['pnpm_audit']['records'] ) ? (int) $provider_status['pnpm_audit']['records'] : 0
		);
		$local_details .= ' ' . sprintf(
			/* translators: 1: WPVulnerability status, 2: WPVulnerability advisory records */
			__( 'WPVulnerability API status: %1$s. WordPress/runtime advisory records: %2$d.', 'aegisify-audit-agent' ),
			! empty( $provider_status['wpvulnerability_api']['status'] ) ? sanitize_text_field( (string) $provider_status['wpvulnerability_api']['status'] ) : __( 'unknown', 'aegisify-audit-agent' ),
			! empty( $provider_status['wpvulnerability_api']['records'] ) ? (int) $provider_status['wpvulnerability_api']['records'] : 0
		);
		if ( 0 === $advisory_total && 0 === $local_risk_total ) {
			$local_details .= ' ' . __( 'No dependency/package-manager advisories or local WordPress component risk signals were returned by the agent for this run.', 'aegisify-audit-agent' );
		}
		if ( $error_total > 0 ) {
			$local_details .= ' ' . sprintf(
				/* translators: %d: number of audit providers that reported an error or unavailable state */
				__( 'Audit providers with execution issues: %d.', 'aegisify-audit-agent' ),
				$error_total
			);
		}
		$provider_status['agent_local_vuln'] = array(
			'status'    => $local_status,
			'records'   => $advisory_total + $local_risk_total,
			'matches'   => $advisory_total + $local_risk_total,
			'error'     => '',
			'details'   => $local_details,
			'source'    => 'agent',
			'execution' => array(
				'engine'            => 'agent_local_vuln',
				'status'            => $local_status,
				'reason'            => $local_details,
				'provider_count'    => count( $audit_provider_map ),
				'executed_count'    => $executed_total,
				'error_count'       => $error_total,
				'advisory_count'    => $advisory_total,
				'local_component_risk_count' => $local_risk_total,
				'plugin_count'      => $plugin_count,
				'theme_count'       => $theme_count,
				'core_version'      => $core_version,
				'local_inventory_status' => ! empty( $local_wordpress_summary['status'] ) ? sanitize_key( (string) $local_wordpress_summary['status'] ) : 'not_run',
				'local_component_advisories' => count( $local_wordpress_advisories ),
				'local_component_results' => count( $local_wordpress_results ),
			),
		);

		if ( $local_risk_total > 0 ) {
			$provider_status['wordpress_component_risk'] = array(
				'status'    => 'success',
				'records'   => $local_risk_total,
				'matches'   => $local_risk_total,
				'error'     => '',
				'details'   => sprintf(
					/* translators: %d: number of WordPress component risk signals */
					__( 'The agent produced %d local WordPress component risk signals from version/update state, inactive component exposure, and automatic-update posture.', 'aegisify-audit-agent' ),
					$local_risk_total
				),
				'source'    => 'agent',
				'execution' => array(
					'engine'       => 'wordpress_component_risk',
					'status'       => 'success',
					'record_count' => $local_risk_total,
					'match_count'  => $local_risk_total,
				),
			);
		}

		$finished_gmt = gmdate( 'Y-m-d H:i:s' );
		$duration_ms  = max( 0, (int) round( ( microtime( true ) - $started_at ) * 1000 ) );
		$summary['scan_profile']         = $scan_profile;
		$summary['provider_status']      = $provider_status;
		$summary['dependency_advisories'] = array(
			'composer' => ! empty( $provider_status['composer_audit']['records'] ) ? (int) $provider_status['composer_audit']['records'] : 0,
			'pip'      => ! empty( $provider_status['pip_audit']['records'] ) ? (int) $provider_status['pip_audit']['records'] : 0,
			'npm'      => ! empty( $provider_status['npm_audit']['records'] ) ? (int) $provider_status['npm_audit']['records'] : 0,
			'yarn'     => ! empty( $provider_status['yarn_audit']['records'] ) ? (int) $provider_status['yarn_audit']['records'] : 0,
			'pnpm'     => ! empty( $provider_status['pnpm_audit']['records'] ) ? (int) $provider_status['pnpm_audit']['records'] : 0,
		);
		$summary['advisory_records_total'] = $advisory_total;
		$summary['wordpress_advisories_total'] = ! empty( $provider_status['wpvulnerability_api']['records'] ) ? (int) $provider_status['wpvulnerability_api']['records'] : 0;
		$summary['wpvulnerability_summary'] = $wpvulnerability_summary;
		$summary['local_inventory_counts'] = array(
			'plugin_count' => $plugin_count,
			'theme_count'  => $theme_count,
			'core_version' => $core_version,
		);
		$summary['scan_started_gmt'] = $started_gmt;
		$summary['scan_finished_gmt'] = $finished_gmt;
		$summary['duration_ms'] = $duration_ms;

		if ( empty( $local_wordpress_advisories ) && ! empty( $flattened_advisories ) ) {
			$local_wordpress_advisories = $flattened_advisories;
		}

		return array(
			'generated_at_gmt'      => ! empty( $inventory_blob['generated_at_gmt'] ) ? sanitize_text_field( (string) $inventory_blob['generated_at_gmt'] ) : $finished_gmt,
			'results'               => $results,
			'summary'               => $summary,
			'provider_status'       => $provider_status,
			'dependency_audits'     => $audits,
			'local_advisories'      => $flattened_advisories,
			'local_wordpress_results'    => $local_wordpress_results,
			'local_wordpress_findings'   => $local_wordpress_findings,
			'local_wordpress_advisories' => $local_wordpress_advisories,
			'local_wordpress_summary'    => $local_wordpress_summary,
			'inventory'             => $inventory,
			'privacy'               => $privacy,
			'tooling_capabilities'  => $tooling,
			'scan_details'          => array(
				'scan_started_gmt'  => $started_gmt,
				'scan_finished_gmt' => $finished_gmt,
				'duration_ms'       => $duration_ms,
				'advisory_total'    => $advisory_total,
			),
		);
	}


	private function build_local_wordpress_risk_findings( array $inventory ) {
		$findings = array();

		$core = ! empty( $inventory['wordpress_core'] ) && is_array( $inventory['wordpress_core'] ) ? $inventory['wordpress_core'] : array();
		if ( ! empty( $core['version'] ) ) {
			if ( ! empty( $core['update_available'] ) && ! empty( $core['latest_version'] ) && sanitize_text_field( (string) $core['latest_version'] ) !== sanitize_text_field( (string) $core['version'] ) ) {
				$findings[] = array(
					'risk_key'          => 'core_update_available',
					'component_type'    => 'wordpress_core',
					'slug'              => 'wordpress',
					'name'              => 'WordPress Core',
					'installed_version' => sanitize_text_field( (string) $core['version'] ),
					'latest_version'    => sanitize_text_field( (string) $core['latest_version'] ),
					'fixed_version'     => sanitize_text_field( (string) $core['latest_version'] ),
					'severity_label'    => 'high',
					'confidence'        => 95,
					'title'             => __( 'WordPress core update available', 'aegisify-audit-agent' ),
					'description'       => sprintf(
						/* translators: 1: installed version, 2: latest version */
						__( 'The installed WordPress core version %1$s is behind the available version %2$s reported on the agent host.', 'aegisify-audit-agent' ),
						sanitize_text_field( (string) $core['version'] ),
						sanitize_text_field( (string) $core['latest_version'] )
					),
				);
			}
		}

		$lists = array(
			'plugin'    => array_merge(
				! empty( $inventory['plugins']['active'] ) && is_array( $inventory['plugins']['active'] ) ? $inventory['plugins']['active'] : array(),
				! empty( $inventory['plugins']['inactive'] ) && is_array( $inventory['plugins']['inactive'] ) ? $inventory['plugins']['inactive'] : array()
			),
			'theme'     => array_merge(
				! empty( $inventory['themes']['active'] ) && is_array( $inventory['themes']['active'] ) ? $inventory['themes']['active'] : array(),
				! empty( $inventory['themes']['inactive'] ) && is_array( $inventory['themes']['inactive'] ) ? $inventory['themes']['inactive'] : array()
			),
			'mu_plugin' => ! empty( $inventory['mu_plugins'] ) && is_array( $inventory['mu_plugins'] ) ? $inventory['mu_plugins'] : array(),
		);

		foreach ( $lists as $component_type => $items ) {
			foreach ( (array) $items as $item ) {
				$item = is_array( $item ) ? $item : array();
				$slug = ! empty( $item['slug'] ) ? sanitize_title( (string) $item['slug'] ) : '';
				if ( '' === $slug ) {
					continue;
				}
				$name              = ! empty( $item['name'] ) ? sanitize_text_field( (string) $item['name'] ) : $slug;
				$installed_version = ! empty( $item['version'] ) ? sanitize_text_field( (string) $item['version'] ) : '';
				$latest_version    = ! empty( $item['latest_version'] ) ? sanitize_text_field( (string) $item['latest_version'] ) : '';
				$is_active         = ! empty( $item['active'] );
				$auto_update       = ! empty( $item['auto_update'] ) || ! empty( $item['auto_updates'] );
				$update_available  = ! empty( $item['update_available'] ) || ( '' !== $latest_version && '' !== $installed_version && $latest_version !== $installed_version );

				if ( $update_available ) {
					$findings[] = array(
						'risk_key'          => $component_type . '_update_available',
						'component_type'    => $component_type,
						'slug'              => $slug,
						'name'              => $name,
						'installed_version' => $installed_version,
						'latest_version'    => $latest_version,
						'fixed_version'     => $latest_version,
						'severity_label'    => ( $is_active || 'mu_plugin' === $component_type ) ? 'medium' : 'low',
						'confidence'        => 85,
						'title'             => __( 'Installed WordPress component is behind the available update', 'aegisify-audit-agent' ),
						'description'       => sprintf(
							/* translators: 1: component name, 2: installed version, 3: latest version */
							__( '%1$s is installed at version %2$s while version %3$s is available on the agent host.', 'aegisify-audit-agent' ),
							$name,
							'' !== $installed_version ? $installed_version : __( 'unknown', 'aegisify-audit-agent' ),
							'' !== $latest_version ? $latest_version : __( 'unknown', 'aegisify-audit-agent' )
						),
						'active'            => $is_active,
						'auto_update'       => $auto_update,
					);
				}

				if ( ! $auto_update && in_array( $component_type, array( 'plugin', 'theme' ), true ) ) {
					$findings[] = array(
						'risk_key'          => $component_type . '_auto_update_disabled',
						'component_type'    => $component_type,
						'slug'              => $slug,
						'name'              => $name,
						'installed_version' => $installed_version,
						'latest_version'    => $latest_version,
						'fixed_version'     => $latest_version,
						'severity_label'    => $is_active ? 'low' : 'info',
						'confidence'        => 65,
						'title'             => __( 'Automatic updates disabled for installed WordPress component', 'aegisify-audit-agent' ),
						'description'       => sprintf(
							/* translators: %s: component name */
							__( '%s has automatic updates disabled on the agent host, which increases exposure when future patches are released.', 'aegisify-audit-agent' ),
							$name
						),
						'active'            => $is_active,
						'auto_update'       => false,
					);
				}

				if ( ! $is_active && in_array( $component_type, array( 'plugin', 'theme' ), true ) ) {
					$findings[] = array(
						'risk_key'          => $component_type . '_inactive_component_present',
						'component_type'    => $component_type,
						'slug'              => $slug,
						'name'              => $name,
						'installed_version' => $installed_version,
						'latest_version'    => $latest_version,
						'fixed_version'     => $latest_version,
						'severity_label'    => 'low',
						'confidence'        => 60,
						'title'             => __( 'Inactive WordPress component remains installed', 'aegisify-audit-agent' ),
						'description'       => sprintf(
							/* translators: %s: component name */
							__( '%s is inactive but still installed on disk, which preserves attack surface and patch-management burden.', 'aegisify-audit-agent' ),
							$name
						),
						'active'            => false,
						'auto_update'       => $auto_update,
					);
				}
			}
		}

		$deduped = array();
		foreach ( $findings as $finding ) {
			$key = sanitize_key( (string) ( ! empty( $finding['risk_key'] ) ? $finding['risk_key'] : 'risk' ) ) . '|' . sanitize_title( (string) ( ! empty( $finding['slug'] ) ? $finding['slug'] : '' ) );
			$deduped[ $key ] = $finding;
		}

		return array_values( $deduped );
	}

	private function build_provider_details( $audit_key, $status, $record_count, array $execution = array(), $error = '' ) {
		$parts = array();
		$reason = ! empty( $execution['reason'] ) ? sanitize_text_field( (string) $execution['reason'] ) : '';
		if ( '' !== $reason ) {
			$parts[] = $reason;
		}
		if ( isset( $execution['manifest_count'] ) ) {
			$parts[] = sprintf(
				/* translators: %d: manifest count */
				__( 'Manifests: %d.', 'aegisify-audit-agent' ),
				absint( $execution['manifest_count'] )
			);
		}
		$parts[] = sprintf(
			/* translators: %d: advisory record count */
			__( 'Records: %d.', 'aegisify-audit-agent' ),
			absint( $record_count )
		);
		if ( isset( $execution['exit_code'] ) && null !== $execution['exit_code'] ) {
			$parts[] = sprintf(
				/* translators: %d: subprocess exit code */
				__( 'Exit code: %d.', 'aegisify-audit-agent' ),
				absint( $execution['exit_code'] )
			);
		}
		if ( ! empty( $execution['stderr_summary'] ) ) {
			$parts[] = sprintf(
				/* translators: %s: sanitized stderr summary */
				__( 'stderr: %s', 'aegisify-audit-agent' ),
				sanitize_text_field( (string) $execution['stderr_summary'] )
			);
		} elseif ( ! empty( $error ) ) {
			$parts[] = sanitize_text_field( (string) $error );
		}
		if ( empty( $parts ) ) {
			$parts[] = sprintf(
				/* translators: %s: audit key */
				__( 'The local %s audit completed without additional execution detail.', 'aegisify-audit-agent' ),
				sanitize_text_field( (string) $audit_key )
			);
		}
		return implode( ' ', array_filter( $parts ) );
	}
}
