<?php

namespace App\Listeners;

use App\Mail\NewDeviceSignInMail;
use App\Services\Devices\DeviceRecognition;
use Illuminate\Auth\Events\Login;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Throwable;

/**
 * One listener for both ways in.
 *
 * The console signs in through App\Livewire\Auth\OperatorLogin and the portal
 * through Fortify — two code paths that share nothing. Both raise Laravel's
 * Login event, and it carries the guard, which is the one thing that tells
 * operators and customers apart (R21). Hooking the event rather than the two
 * controllers means neither can be changed in a way that quietly stops
 * recording sign-ins.
 *
 * Nothing here may prevent a sign-in. Recognising a device is a safeguard, and
 * a safeguard that locks the owner out when it breaks has stopped being one —
 * so a failure is logged and swallowed. This is a deliberate exception to
 * failing loudly, and the reason is written here so nobody removes it as an
 * oversight.
 */
class RecordSignInDevice
{
    public function __construct(
        private readonly DeviceRecognition $devices,
        private readonly Request $request,
    ) {}

    public function handle(Login $event): void
    {
        try {
            $outcome = $this->devices->recognise($event->user, $event->guard, $this->request);
            $this->devices->attachSession($outcome->device, $this->request);

            if (! $outcome->shouldWarn) {
                return;
            }

            $address = $event->user->getAttribute('email');

            if (! is_string($address) || $address === '') {
                return;
            }

            // Queued: a sign-in must not wait on a mail server, and this one
            // runs while somebody is looking at a spinner on the login button.
            $mail = new NewDeviceSignInMail(
                name: (string) ($event->user->getAttribute('name') ?? ''),
                device: $outcome->device,
                guard: $event->guard,
            );
            Mail::mailer($mail->mailer)->to($address)->queue($mail);
        } catch (Throwable $e) {
            Log::warning('Could not record the device for a sign-in', [
                'guard' => $event->guard,
                'exception' => $e->getMessage(),
            ]);
        }
    }
}
