<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Sentry\Event;
use Sentry\EventHint;
use Sentry\SentrySdk;

/**
 * Blindaje de PII para Sentry, config-cache-safe.
 *
 * NO usamos `before_send` en config/sentry.php porque un closure allí rompería
 * `php artisan config:cache` (parte de `optimize` en cada deploy — los closures
 * no serializan). En su lugar registramos el callback en código, mutando las
 * opciones del cliente ya construido por sentry-laravel.
 *
 * Defensa en profundidad: aunque `send_default_pii=false` y `sql_bindings=false`
 * ya evitan enviar cuerpos de request y parámetros SQL, filtramos por si algún
 * path adjunta datos sensibles (montos, documentos, teléfonos, credenciales).
 */
class SentryPiiScrubberServiceProvider extends ServiceProvider
{
    /** @var list<string> Claves sensibles, comparadas en minúsculas. */
    private const SCRUB_KEYS = [
        'password', 'password_confirmation', 'current_password', 'token', 'secret', 'api_key',
        'monto', 'amount', 'saldo', 'valor', 'cuota', 'capital', 'interes',
        'documento', 'cedula', 'nit', 'identificacion', 'dni',
        'telefono', 'phone', 'whatsapp', 'celular', 'email', 'correo',
    ];

    public function boot(): void
    {
        $client = SentrySdk::getCurrentHub()->getClient();

        if ($client === null) {
            return;
        }

        $options = $client->getOptions();
        $previous = $options->getBeforeSendCallback();

        $options->setBeforeSendCallback(function (Event $event, ?EventHint $hint) use ($previous): ?Event {
            $request = $event->getRequest();

            if (isset($request['data']) && is_array($request['data'])) {
                $request['data'] = $this->scrub($request['data']);
                $event->setRequest($request);
            }

            return $previous($event, $hint);
        });
    }

    /**
     * Reemplaza recursivamente los valores de claves sensibles por "[filtered]".
     *
     * @param  array<array-key, mixed>  $data
     * @return array<array-key, mixed>
     */
    private function scrub(array $data): array
    {
        foreach ($data as $key => $value) {
            if (is_array($value)) {
                $data[$key] = $this->scrub($value);
            } elseif (in_array(strtolower((string) $key), self::SCRUB_KEYS, true)) {
                $data[$key] = '[filtered]';
            }
        }

        return $data;
    }
}
