<?php

/**
 * Deterministic load/activation safety gate for generated artifact PHP.
 *
 * @package LolaCore\Builder\Safety
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Builder\Safety;

use LolaCore\Builder\Artifact\FilesMap;

if (! defined('ABSPATH')) {
	exit;
}

/**
 * Runs Capa A static safety rules on generated PHP artifacts.
 */
class StaticSafetyGate {

	private SafetyRuleRegistry $registry;

	public function __construct( ?SafetyRuleRegistry $registry = null ) {
		$this->registry = $registry ?? new SafetyRuleRegistry();
	}

	/**
	 * @param array{php?: string, slug?: string, dependencies?: array<int, string>} $artifact
	 * @return array{
	 *   blocking: bool,
	 *   confidence_cap: ?int,
	 *   findings: array<int, array{
	 *     severity: 'fatal'|'error'|'warning',
	 *     code: string,
	 *     message: string,
	 *     line?: int
	 *   }>
	 * }
	 */
	public function analyze( array $artifact ): array {
		$php = isset($artifact['php']) ? (string) $artifact['php'] : '';

		$dependencies = array();
		if (isset($artifact['dependencies']) && is_array($artifact['dependencies'])) {
			$dependencies = $artifact['dependencies'];
		}

		$context = new SafetyContext(
			isset($artifact['slug']) ? (string) $artifact['slug'] : '',
			$dependencies
		);

		return $this->summarize($this->runRules($php, $context));
	}

	/**
	 * Analyze every PHP file in a files map under one artifact context.
	 *
	 * Findings across files are merged; blocking/confidence semantics match
	 * analyze() exactly.
	 *
	 * @param array<int, string> $dependencies
	 * @return array{
	 *   blocking: bool,
	 *   confidence_cap: ?int,
	 *   findings: array<int, array{
	 *     severity: 'fatal'|'error'|'warning',
	 *     code: string,
	 *     message: string,
	 *     line?: int
	 *   }>
	 * }
	 */
	public function analyzeFiles( FilesMap $files, string $slug = '', array $dependencies = array() ): array {
		$context  = new SafetyContext($slug, $dependencies);
		$findings = array();

		foreach ($files->phpFiles() as $php) {
			$findings = array_merge($findings, $this->runRules($php, $context));
		}

		return $this->summarize($findings);
	}

	/**
	 * @return array<int, array{severity: string, code: string, message: string, line?: int}>
	 */
	private function runRules( string $php, SafetyContext $context ): array {
		$findings = array();

		foreach ($this->registry->getRules() as $rule) {
			$findings = array_merge($findings, $rule->analyze($php, $context));
		}

		return $findings;
	}

	/**
	 * @param array<int, array{severity: string, code: string, message: string, line?: int}> $findings
	 * @return array{blocking: bool, confidence_cap: ?int, findings: array<int, array{severity: string, code: string, message: string, line?: int}>}
	 */
	private function summarize( array $findings ): array {
		$blocking      = false;
		$confidenceCap = null;
		foreach ($findings as $finding) {
			$severity = (string) ( $finding['severity'] ?? '' );
			if ($severity === 'fatal' || $severity === 'error') {
				$blocking = true;
			}
			if ($severity === 'warning') {
				$confidenceCap = $confidenceCap === null ? 70 : min($confidenceCap, 70);
			}
		}

		return array(
			'blocking'       => $blocking,
			'confidence_cap' => $confidenceCap,
			'findings'       => $findings,
		);
	}
}
