<?php

namespace App\Providers;

use App\Events\ServiceEventOccurred;
use App\Listeners\PlatformServiceEventListener;
use App\Models\User;
use App\Services\Care\OrganizationResolver;
use App\Services\Care\PlanService;
use App\Services\Care\SpecialtyModuleService;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Request-scoped memoization for specialty nav / branch scope (avoids N+1 per module).
        $this->app->singleton(OrganizationResolver::class);
        $this->app->singleton(SpecialtyModuleService::class);
    }

    public function boot(): void
    {
        Event::listen(ServiceEventOccurred::class, PlatformServiceEventListener::class);

        RateLimiter::for('care-device', function (Request $request) {
            $token = $request->header('X-Care-Device-Token')
                ?? $request->header('X-Device-Token')
                ?? $request->bearerToken()
                ?? $request->ip();

            return Limit::perMinute(60)->by((string) $token);
        });

        View::composer([
            'partials.sidebar',
            'partials.topbar-desktop-widgets',
            'partials.afia',
            'partials.upgrade-banner',
            'care.dashboard',
            'components.app-layout',
        ], function ($view) {
            /** @var User|null $user */
            $user = auth()->user();
            $planKey = 'free';
            $isPro = false;
            $isEnterprise = false;
            $hasPaidPlan = false;

            if ($user) {
                $organization = app(OrganizationResolver::class)->resolveForUser($user);
                if ($organization) {
                    $plans = app(PlanService::class);
                    $planKey = $plans->planKey($organization);
                    $isPro = $planKey === 'pro';
                    $isEnterprise = $planKey === 'enterprise';
                    $hasPaidPlan = $plans->hasPaidPlan($organization);
                }
            }

            $view->with([
                'planKey' => $planKey,
                'isPro' => $isPro,
                'isEnterprise' => $isEnterprise,
                'hasPaidPlan' => $hasPaidPlan,
            ]);
        });

        View::composer(['partials.topbar'], function ($view) {
            $view->with(\App\Support\MobileTopbar::resolve());
        });

        View::composer(['partials.launcher', 'partials.topbar-desktop-widgets', 'components.app-layout'], function () {
            $user = auth()->user();
            if (! $user) {
                return;
            }

            $member = app(\App\Services\Care\OrganizationResolver::class)->memberFor($user);
            $permissions = app(\App\Services\Care\CarePermissions::class);

            if (! session()->has(\App\Support\StaffUx::SESSION_KEY)) {
                try {
                    $access = app(\App\Services\Identity\IdentityTeamClient::class)
                        ->appAccess($user->ownerRef());
                    \App\Support\StaffUx::remember(
                        $permissions->filterStaffAppAccess($member, $access)
                    );
                } catch (\Throwable) {
                    // Leave fail-open defaults until Identity is available.
                }

                return;
            }

            // Stale Identity grants may still list POS — strip for Care cashiers.
            $cached = session(\App\Support\StaffUx::SESSION_KEY);
            if (! is_array($cached) || ! empty($cached['full_access'])) {
                return;
            }

            $filtered = $permissions->filterStaffAppAccess($member, [
                'full_access' => false,
                'apps' => array_values(array_map('strval', (array) ($cached['apps'] ?? []))),
                'show_hub' => (bool) ($cached['show_hub'] ?? false),
                'show_billing' => (bool) ($cached['show_billing'] ?? false),
            ]);

            if ($filtered['apps'] !== array_values(array_map('strval', (array) ($cached['apps'] ?? [])))
                || (bool) ($filtered['show_hub'] ?? false) !== (bool) ($cached['show_hub'] ?? false)) {
                \App\Support\StaffUx::remember($filtered);
            }
        });
    }
}
