<?php

namespace App\Providers;

use App\Models\User;
use App\Services\AuditLog;
use Illuminate\Auth\Events\Login;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;

/**
 * Ported from leolanka-inertia's FortifyServiceProvider (docs/migration-plan.md
 * §5) — the parts that are NOT Fortify-specific: named rate limiters actually
 * consumed by our own Login page / PinLoginController, and the centralized
 * `Illuminate\Auth\Events\Login` listener that stamps last_login_at/ip and
 * writes the `user.login` audit entry for every login path (password, TOTP
 * challenge, PIN, remember-cookie restore — anything that calls
 * `Auth::login()` fires this event automatically, Fortify or not).
 *
 * Not ported: the `two-factor` rate limiter (was consumed by Fortify's own
 * TOTP challenge controller, which we don't use — Filament's native
 * AppAuthentication has its own internal setup-flow rate limiting) and the
 * Fortify-specific TwoFactorAuthentication{Enabled,Confirmed,Disabled,Failed}
 * / RecoveryCodeReplaced event listeners (those events are never fired
 * outside Fortify's own actions). The enabled/disabled audit trail is
 * preserved instead directly in User::saveAppAuthenticationSecret() — see
 * that method and the Decisions Log entry for what's intentionally not
 * carried over (per-attempt 2FA-failed and recovery-code-used audit entries).
 */
class AuthEventsServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        RateLimiter::for('login', function (Request $request) {
            $throttleKey = Str::transliterate(Str::lower((string) $request->input('email')).'|'.$request->ip());

            return Limit::perMinute(5)->by($throttleKey);
        });

        RateLimiter::for('pin-login', function (Request $request) {
            return Limit::perMinute(10)->by($request->ip());
        });

        Event::listen(Login::class, function (Login $event): void {
            if ($event->user instanceof User) {
                $event->user->forceFill([
                    'last_login_at' => now(),
                    'last_login_ip' => request()->ip(),
                ])->save();

                AuditLog::record('user.login', $event->user, [
                    'ip' => request()->ip(),
                    'user_agent' => substr((string) request()->userAgent(), 0, 255),
                ]);
            }
        });
    }
}
