<?php
declare(strict_types=1);

namespace App\Services;

use RuntimeException;

final class SystemIntegrityService
{
    /** @return array{summary:array<string,int>,files:array<int,array<string,string>>,strict:bool,ok:bool} */
    public function report(): array
    {
        $configFile = BASE_PATH . '/config/integrity.php';
        $entries = is_file($configFile) ? require $configFile : [];
        $crypto = is_file(BASE_PATH . '/config/security_crypto.php') ? require BASE_PATH . '/config/security_crypto.php' : [];
        $files = [];
        $summary = ['ok' => 0, 'modified' => 0, 'missing' => 0];

        foreach (is_array($entries) ? $entries : [] as $relative => $expected) {
            $relative = ltrim(str_replace('\\', '/', (string)$relative), '/');
            $absolute = BASE_PATH . '/' . $relative;
            if (!is_file($absolute)) {
                $status = 'missing';
                $actual = '';
            } else {
                $actual = (string)hash_file('sha256', $absolute);
                $status = hash_equals(strtolower((string)$expected), strtolower($actual)) ? 'ok' : 'modified';
            }
            $summary[$status]++;
            $files[] = ['path' => $relative, 'status' => $status, 'expected' => (string)$expected, 'actual' => $actual];
        }

        $strict = (bool)($crypto['integrity_strict'] ?? false);
        $ok = $summary['modified'] === 0 && $summary['missing'] === 0;
        if (!$ok) $this->log($files, (string)($crypto['integrity_log'] ?? BASE_PATH . '/storage/logs/integrity.log'));
        return ['summary' => $summary, 'files' => $files, 'strict' => $strict, 'ok' => $ok];
    }

    public function enforce(): void
    {
        $report = $this->report();
        if ($report['strict'] && !$report['ok']) {
            throw new RuntimeException('Intégrité du noyau AXIOM compromise. Démarrage refusé en mode strict.');
        }
    }

    private function log(array $files, string $path): void
    {
        $dir = dirname($path);
        if (!is_dir($dir)) @mkdir($dir, 0770, true);
        $anomalies = array_values(array_filter($files, static fn(array $f): bool => $f['status'] !== 'ok'));
        $line = json_encode(['at' => gmdate(DATE_ATOM), 'event' => 'core_integrity_mismatch', 'files' => $anomalies], JSON_UNESCAPED_SLASHES) . PHP_EOL;
        @file_put_contents($path, $line, FILE_APPEND | LOCK_EX);
    }
}
