<?php

namespace App\Modules\AntiTheft\Infrastructure;

use App\Modules\AntiTheft\Application\RuleTriggerStore;
use App\Modules\AntiTheft\Domain\SecuritySignal;
use App\Modules\AntiTheft\Domain\TheftRule;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use RuntimeException;

final class DatabaseRuleTriggerStore implements RuleTriggerStore
{
    public function lastTriggeredAt(string $deviceUuid): array
    {
        $deviceId = DB::table('devices')->where('uuid', $deviceUuid)->value('id');
        if ($deviceId === null) {
            return [];
        }

        return DB::table('device_security_logs')
            ->where('device_id', $deviceId)
            ->where('event_source', 'rule_engine')
            ->selectRaw('security_event, MAX(created_at) AS triggered_at')
            ->groupBy('security_event')
            ->get()
            ->mapWithKeys(fn (object $row): array => [
                (string) $row->security_event => strtotime((string) $row->triggered_at),
            ])
            ->all();
    }

    public function record(SecuritySignal $signal, array $rules): void
    {
        $deviceId = DB::table('devices')->where('uuid', $signal->deviceUuid)->value('id');
        if ($deviceId === null) {
            throw new RuntimeException('Cannot record a trigger for an unknown device.');
        }

        $rows = array_map(fn (TheftRule $rule): array => [
            'uuid' => (string) Str::uuid(),
            'device_id' => $deviceId,
            'theft_event_id' => null,
            'security_event' => $rule->code,
            'security_level' => $rule->risk->value,
            'event_source' => 'rule_engine',
            'event_data' => json_encode([
                'signal' => $signal->type->value,
                'confidence' => $signal->confidence,
                'magnitude' => $signal->magnitude,
                'context' => $signal->context,
            ], JSON_THROW_ON_ERROR),
            'payload_hash' => hash('sha256', $signal->deviceUuid.'|'.$rule->code.'|'.$signal->occurredAt->format(DATE_ATOM)),
            'created_at' => $signal->occurredAt->format('Y-m-d H:i:s'),
        ], $rules);

        DB::table('device_security_logs')->insert($rows);
    }
}
