<?php
/**
 * WinRacing V62.0 — Pre-Race Production Readiness Gate
 * Final pre-race certification layer combining V60 OS health + V61 leakage audit.
 * Read-only / advisory-only. No DB writes, schema changes, score mutation or live-weight changes.
 */
final class ChairmanProductionReadinessGateV62
{
    public function certify(array $source, array $osData, array $leakageData, $raceDate = '', $venue = '')
    {
        $checks = array();
        $findings = array();

        $this->check($checks, $findings, 'SOURCE_STATUS', isset($source['status']) && in_array($source['status'], array('OK','READY','COMPLETE'), true), 'CRITICAL', 'Source snapshot is not ready.');
        $this->check($checks, $findings, 'PRE_RACE_CONTRACT', isset($leakageData['leakage_summary']['audit_state']) && $leakageData['leakage_summary']['audit_state'] === 'PASS', 'CRITICAL', 'V61 leakage audit did not return PASS.');
        $this->check($checks, $findings, 'RESULTS_ISOLATION', !$this->containsTrueFlag($source, array('results_used','result_available')), 'CRITICAL', 'A result availability flag is true in the pre-race source.');

        $osState = isset($osData['os_summary']['os_state']) ? (string)$osData['os_summary']['os_state'] : 'UNKNOWN';
        $osHealth = isset($osData['os_summary']['health_score']) ? (float)$osData['os_summary']['health_score'] : 0.0;
        $this->check($checks, $findings, 'OS_HEALTH', in_array($osState, array('OPTIMAL','STABLE'), true) && $osHealth >= 75, 'WARNING', 'V60 OS health is below production threshold.');

        $ranking = isset($source['final_chairman_ranking']) && is_array($source['final_chairman_ranking']) ? $source['final_chairman_ranking'] : array();
        $dashboard = isset($source['ultimate_dashboard']) && is_array($source['ultimate_dashboard']) ? $source['ultimate_dashboard'] : array();
        $memory = isset($source['memory_records']) && is_array($source['memory_records']) ? $source['memory_records'] : array();
        $clusters = isset($source['pattern_clusters']) && is_array($source['pattern_clusters']) ? $source['pattern_clusters'] : array();

        $this->check($checks, $findings, 'DECISION_OUTPUT', count($ranking) > 0 || count($dashboard) > 0, 'CRITICAL', 'No final chairman ranking/dashboard output is available.');
        $this->check($checks, $findings, 'MEMORY_INPUT', count($memory) > 0, 'WARNING', 'No chairman memory records are available.');
        $this->check($checks, $findings, 'PATTERN_INPUT', count($clusters) > 0, 'WARNING', 'No pattern clusters are available.');
        $this->check($checks, $findings, 'NUMERIC_INTEGRITY', $this->numericIntegrity($source), 'CRITICAL', 'Non-finite numeric value detected in decision payload.');
        $this->check($checks, $findings, 'IMMUTABILITY_CONTRACT', $this->immutable($source, $osData, $leakageData), 'CRITICAL', 'An upstream layer reported a prohibited live mutation.');

        $critical = 0; $warning = 0;
        foreach ($findings as $finding) {
            if ($finding['severity'] === 'CRITICAL') { $critical++; }
            elseif ($finding['severity'] === 'WARNING') { $warning++; }
        }

        $score = max(0, 100 - ($critical * 35) - ($warning * 7));
        $gate = $critical > 0 ? 'BLOCKED' : ($warning > 0 ? 'READY_WITH_REVIEW' : 'READY');
        $state = $critical > 0 ? 'FAIL' : ($warning > 0 ? 'REVIEW' : 'PASS');

        return array(
            'status' => 'OK',
            'engine' => 'V62',
            'engine_version' => '62.0.0',
            'race_date' => (string)$raceDate,
            'venue' => (string)$venue,
            'mode' => 'READ_ONLY_ADVISORY',
            'live_weights_changed' => false,
            'database_schema_changed' => false,
            'source_decisions_changed' => false,
            'readiness_summary' => array(
                'readiness_state' => $state,
                'production_gate' => $gate,
                'readiness_score' => round($score, 1),
                'check_count' => count($checks),
                'passed_count' => count($checks) - count($findings),
                'critical_count' => $critical,
                'warning_count' => $warning,
                'os_state' => $osState,
                'os_health_score' => round($osHealth, 1),
                'ranking_count' => count($ranking),
                'dashboard_count' => count($dashboard),
                'memory_count' => count($memory),
                'cluster_count' => count($clusters)
            ),
            'checks' => $checks,
            'findings' => $findings,
            'certification_contract' => array(
                'pre_race_only' => true,
                'results_must_be_unavailable' => true,
                'v61_leakage_pass_required' => true,
                'db_write_permitted' => false,
                'schema_change_permitted' => false,
                'live_weight_change_permitted' => false,
                'production_use_permitted' => $critical === 0
            )
        );
    }

    private function check(array &$checks, array &$findings, $name, $passed, $severity, $message)
    {
        $checks[] = array('check'=>$name, 'status'=>$passed ? 'PASS' : 'FAIL', 'severity'=>$severity);
        if (!$passed) {
            $findings[] = array('type'=>$name, 'severity'=>$severity, 'message'=>$message);
        }
    }

    private function containsTrueFlag(array $data, array $keys)
    {
        foreach ($data as $key => $value) {
            $k = is_string($key) ? strtolower($key) : '';
            if (in_array($k, $keys, true) && $value === true) { return true; }
            if (is_array($value) && $this->containsTrueFlag($value, $keys)) { return true; }
        }
        return false;
    }

    private function numericIntegrity($value)
    {
        if (is_float($value) && (is_nan($value) || is_infinite($value))) { return false; }
        if (!is_array($value)) { return true; }
        foreach ($value as $child) {
            if (!$this->numericIntegrity($child)) { return false; }
        }
        return true;
    }

    private function immutable(array $source, array $osData, array $leakageData)
    {
        foreach (array($source, $osData, $leakageData) as $payload) {
            if (isset($payload['live_weights_changed']) && $payload['live_weights_changed'] === true) { return false; }
            if (isset($payload['database_schema_changed']) && $payload['database_schema_changed'] === true) { return false; }
            if (isset($payload['source_decisions_changed']) && $payload['source_decisions_changed'] === true) { return false; }
        }
        return true;
    }
}
