<?php

namespace App\Providers;

use App\Domains\Notification\Events\PasswordResetRequested;
use App\Domains\Notification\Events\UserRegistered;
use App\Domains\Notification\Listeners\SendPasswordResetEmail;
use App\Domains\Notification\Listeners\SendPurchaseConfirmedEmail;
use App\Domains\Notification\Listeners\SendWelcomeEmail;
use App\Domains\Purchase\Events\PurchasePaid;
use App\Domains\Ticket\Listeners\GenerateTicketsForPaidPurchase;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Event::listen(PurchasePaid::class, GenerateTicketsForPaidPurchase::class);
        Event::listen(PurchasePaid::class, SendPurchaseConfirmedEmail::class);
        Event::listen(UserRegistered::class, SendWelcomeEmail::class);
        Event::listen(PasswordResetRequested::class, SendPasswordResetEmail::class);

        RateLimiter::for('login', function (Request $request): array {
            $normalizedEmail = mb_strtolower(trim((string) $request->input('email')));
            $emailFingerprint = hash_hmac(
                'sha256',
                $normalizedEmail,
                (string) config('app.key'),
            );
            $ipAddress = $request->ip() ?? 'unknown';

            return [
                Limit::perMinute(
                    max(1, (int) config('login-security.rate_limit_per_minute'))
                )->by("login:identity:{$emailFingerprint}:{$ipAddress}"),
                Limit::perMinute(
                    max(1, (int) config('login-security.ip_rate_limit_per_minute'))
                )->by("login:ip:{$ipAddress}"),
            ];
        });

        Builder::macro('paginateFromRequest', function (int $defaultPerPage = 15, int $maxPerPage = 100, ?int $page = null) {
            /** @var Builder $this */
            $perPage = (int) request()->query('per_page', $defaultPerPage);
            $page = $page ?? (int) request()->query('page', 1);

            if ($perPage <= 0) {
                $perPage = $defaultPerPage;
            }
            if ($perPage > $maxPerPage) {
                $perPage = $maxPerPage;
            }
            if ($page <= 0) {
                $page = 1;
            }

            return $this->paginate(perPage: $perPage, page: $page);
        });
    }
}
