<?php

namespace App\Providers;

use App\Domain\Identity\Services\PermissionService;
use App\Domain\Shared\Context\BranchContext;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        // One branch context per request — and per Livewire round-trip, since
        // each of those is its own request.
        $this->app->scoped(BranchContext::class);

        // The switch BranchScope reads. Scoped for the same reason: it holds
        // per-request state (which branch, and whether a report has currently
        // suppressed enforcement), and a singleton would leak that between
        // requests in a long-lived worker.
        $this->app->scoped(\App\Domain\Shared\Context\BranchScopeState::class);

        // One resolved brand per request. The per-request memo inside it is
        // what stops a Livewire round-trip re-reading the whole branding group.
        $this->app->scoped(\App\Domain\Shared\Services\BrandingService::class);

        // One account resolver too — it caches chart-of-accounts lookups by
        // code for the life of the request.
        $this->app->scoped(\App\Domain\Financial\Services\LedgerAccountResolver::class);

        // The resolver memoises which participants an account speaks for, and
        // the portal context memoises which of them is selected. Both are
        // per-request, and a Livewire round-trip is its own request.
        $this->app->scoped(\App\Domain\Identity\Services\GuardianResolver::class);
        $this->app->scoped(\App\Domain\Shared\Context\PortalContext::class);

        // The branch's word for "member". Consulted by the sidebar and by most
        // list screens, so the per-branch memo inside it is what keeps a page
        // render at one query instead of one per label.
        $this->app->scoped(\App\Domain\Identity\Services\TerminologyService::class);
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        // Only for the 500-error handler's diagnostics. Left on unconditionally
        // it retains every statement of every request in memory for no benefit.
        if (config('app.debug')) {
            DB::enableQueryLog();
        }

        Gate::before(function ($user, $ability) {
            return app(PermissionService::class)->can($user, $ability) ?: null;
        });

        Blade::if('permission', function (string $permission) {
            $user = auth()->user();
            if (!$user) {
                return false;
            }
            return app(PermissionService::class)->can($user, $permission);
        });
    }
}
