<?php
declare(strict_types=1);
namespace App\Platform\Soc\Correlation;

use App\Core\Database;

final class IncidentManager
{
    /** @param array<string,mixed> $rule @param list<array<string,mixed>> $events */
    public function createOrMerge(array $rule, array $events, int $score, string $severity, string $correlationKey): string
    {
        $connection = Database::connection();
        $existing = $connection->prepare(
            'SELECT incident_uuid FROM system_security_incidents '
            . 'WHERE rule_id=:rule_id AND correlation_key=:correlation_key AND status IN (\'open\',\'investigating\') '
            . 'ORDER BY id DESC LIMIT 1'
        );
        $existing->execute(['rule_id'=>(int)$rule['id'], 'correlation_key'=>$correlationKey]);
        $uuid = $existing->fetchColumn();
        if (is_string($uuid) && $uuid !== '') {
            $update = $connection->prepare(
                'UPDATE system_security_incidents SET risk_score=GREATEST(risk_score,:risk_score),severity=:severity,'
                . 'event_count=event_count+:event_count,last_event_at=:last_event_at,updated_at=NOW() WHERE incident_uuid=:incident_uuid'
            );
            $update->execute([
                'risk_score'=>$score,'severity'=>$severity,'event_count'=>count($events),
                'last_event_at'=>(string)$events[count($events)-1]['occurred_at'],'incident_uuid'=>$uuid,
            ]);
        } else {
            $uuid = self::uuidV4();
            $first = $events[0];
            $last = $events[count($events)-1];
            $insert = $connection->prepare(
                'INSERT INTO system_security_incidents '
                . '(incident_uuid,rule_id,correlation_key,title,description,status,severity,risk_score,event_count,user_id,organisation_id,session_reference,ip_hash,module,first_event_at,last_event_at,created_at,updated_at) '
                . 'VALUES (:incident_uuid,:rule_id,:correlation_key,:title,:description,\'open\',:severity,:risk_score,:event_count,:user_id,:organisation_id,:session_reference,:ip_hash,:module,:first_event_at,:last_event_at,NOW(),NOW())'
            );
            $insert->execute([
                'incident_uuid'=>$uuid,'rule_id'=>(int)$rule['id'],'correlation_key'=>$correlationKey,
                'title'=>(string)$rule['name'],'description'=>(string)$rule['description'],'severity'=>$severity,
                'risk_score'=>$score,'event_count'=>count($events),'user_id'=>$first['user_id'] ?? null,
                'organisation_id'=>$first['organisation_id'] ?? null,'session_reference'=>$first['session_reference'] ?? null,
                'ip_hash'=>$first['ip_hash'] ?? null,'module'=>$first['module'] ?? null,
                'first_event_at'=>(string)$first['occurred_at'],'last_event_at'=>(string)$last['occurred_at'],
            ]);
        }
        $this->attachEvents($uuid, $events);
        return $uuid;
    }

    /** @param list<array<string,mixed>> $events */
    private function attachEvents(string $incidentUuid, array $events): void
    {
        $statement = Database::connection()->prepare(
            'INSERT IGNORE INTO system_security_incident_events (incident_uuid,event_uuid,linked_at) '
            . 'VALUES (:incident_uuid,:event_uuid,NOW())'
        );
        foreach ($events as $event) {
            $statement->execute(['incident_uuid'=>$incidentUuid,'event_uuid'=>(string)$event['event_uuid']]);
        }
    }

    private static function uuidV4(): string
    {
        $bytes=random_bytes(16); $bytes[6]=chr((ord($bytes[6])&15)|64); $bytes[8]=chr((ord($bytes[8])&63)|128);
        $hex=bin2hex($bytes);
        return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20);
    }
}
