<?php

namespace App\Services\Security;

use App\Models\SecurityEventLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

class SecurityEventLogger
{
    public function log(string $eventType, string $severity = 'warning', array $metadata = [], ?Request $request = null): void
    {
        $request = $request ?: request();

        try {
            $safeMetadata = $this->redact($metadata);

            $payload = [
                'event_type' => $this->limit($eventType, 120),
                'severity' => $this->limit($severity, 30),
                'user_id' => optional($request->user())->id,
                'user_email' => optional($request->user())->email,
                'ip_address' => $this->limit((string) $request->ip(), 100),
                'user_agent' => $this->limit((string) $request->userAgent(), 600),
                'method' => $this->limit((string) $request->method(), 20),
                'url' => $this->limit((string) $request->fullUrl(), 1500),
                'route_name' => optional($request->route())->getName(),
                'session_id_hash' => $request->hasSession() ? hash('sha256', (string) $request->session()->getId()) : null,
                'request_id' => $request->headers->get('X-Request-Id') ?: (string) Str::uuid(),
                'metadata' => $this->limit(json_encode($safeMetadata, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '{}', 60000),
                'detected_value_hash' => isset($metadata['detected_value']) ? hash('sha256', (string) $metadata['detected_value']) : null,
                'detected_value_preview' => isset($metadata['detected_value']) ? $this->limit($this->safePreview((string) $metadata['detected_value']), 300) : null,
                'status' => $this->limit($metadata['status'] ?? 'recorded', 50),
            ];

            if (Schema::hasTable('security_event_logs')) {
                SecurityEventLog::create($payload);
                return;
            }

            Log::warning('NGBVD security event', $payload);
        } catch (\Throwable $e) {
            Log::warning('NGBVD security event logging failed', [
                'event_type' => $eventType,
                'message' => $e->getMessage(),
            ]);
        }
    }

    public function redact($value)
    {
        $blocked = [
            'password', 'password_confirmation', 'password_confirmatio', 'cpassword',
            'token', 'api_token', 'client_secret', 'client_secret_hash', 'secret',
            'authorization', 'cookie', 'set-cookie', 'x-client-secret', 'x-signature',
            'remember_token', '_token',
        ];

        if (is_array($value)) {
            $clean = [];
            foreach ($value as $key => $item) {
                $lower = strtolower((string) $key);
                if (in_array($lower, $blocked, true) || Str::contains($lower, ['password', 'secret', 'token', 'cookie', 'signature'])) {
                    $clean[$key] = '***REDACTED***';
                } else {
                    $clean[$key] = $this->redact($item);
                }
            }
            return $clean;
        }

        if (is_string($value) && strlen($value) > 500) {
            return $this->limit($this->safePreview($value), 500);
        }

        return $value;
    }

    private function safePreview(string $value): string
    {
        return preg_replace('/[^\P{C}\t\r\n]+/u', '', $value) ?: '';
    }

    private function limit($value, int $limit): ?string
    {
        if ($value === null) {
            return null;
        }

        return Str::limit((string) $value, $limit, '');
    }
}
