<?php

namespace App\Filament\Resources;

use App\Filament\Resources\TenantResource\Pages;
use App\Filament\Resources\TenantResource\RelationManagers;
use App\Http\Controllers\RbacDelegatedAuthController;
use App\Jobs\BulkTenantSyncJob;
use App\Jobs\SyncPoliciesJob;
use App\Models\EntraGroup;
use App\Models\EntraRoleDefinition;
use App\Models\ProviderConnection;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\RoleCapabilityMap;
use App\Services\Directory\EntraGroupLabelResolver;
use App\Services\Directory\RoleDefinitionsSyncService;
use App\Services\Graph\GraphClientInterface;
use App\Services\Intune\AuditLogger;
use App\Services\Intune\RbacOnboardingService;
use App\Services\OperationRunService;
use App\Services\Operations\BulkSelectionIdentity;
use App\Services\Verification\StartVerification;
use App\Support\Auth\Capabilities;
use App\Support\Auth\UiTooltips;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Badges\TagBadgeRenderer;
use App\Support\Filament\TablePaginationProfiles;
use App\Support\OperationRunLinks;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\OpsUx\OpsUxBrowserEvents;
use App\Support\Rbac\UiEnforcement;
use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Workspaces\WorkspaceContext;
use BackedEnum;
use Filament\Actions;
use Filament\Actions\ActionGroup;
use Filament\Actions\BulkActionGroup;
use Filament\Forms;
use Filament\Infolists;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use UnitEnum;

class TenantResource extends Resource
{
    // ... [Properties Omitted for Brevity] ...
    protected static ?string $model = Tenant::class;

    protected static bool $isDiscovered = false;

    protected static bool $isScopedToTenant = false;

    protected static ?string $recordTitleAttribute = 'name';

    protected static ?string $recordRouteKeyName = 'external_id';

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-building-office-2';

    protected static string|UnitEnum|null $navigationGroup = 'Settings';

    /**
     * Tenant creation is handled exclusively by the onboarding wizard.
     * The CRUD create page has been removed.
     */
    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        $user = auth()->user();

        if (! $user instanceof User) {
            return false;
        }

        /** @var CapabilityResolver $resolver */
        $resolver = app(CapabilityResolver::class);

        return $record instanceof Tenant
            && $resolver->can($user, $record, Capabilities::TENANT_MANAGE);
    }

    public static function canDelete(Model $record): bool
    {
        $user = auth()->user();

        if (! $user instanceof User) {
            return false;
        }

        /** @var CapabilityResolver $resolver */
        $resolver = app(CapabilityResolver::class);

        return $record instanceof Tenant
            && $resolver->can($user, $record, Capabilities::TENANT_DELETE);
    }

    public static function canDeleteAny(): bool
    {
        $user = auth()->user();

        if (! $user instanceof User) {
            return false;
        }

        return static::userCanDeleteAnyTenant($user);
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
            ->satisfy(ActionSurfaceSlot::ListHeader, 'List page provides a capability-gated create action.')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ViewAction->value)
            ->satisfy(ActionSurfaceSlot::ListRowMoreMenu, 'Row-level secondary actions are grouped under "More".')
            ->satisfy(ActionSurfaceSlot::ListBulkMoreGroup, 'Bulk actions are grouped under "More".')
            ->satisfy(ActionSurfaceSlot::ListEmptyState, 'Create action is reused in the list empty state.')
            ->satisfy(ActionSurfaceSlot::DetailHeader, 'Tenant view page exposes header actions via an action group.');
    }

    private static function userCanManageAnyTenant(User $user): bool
    {
        return $user->tenantMemberships()
            ->pluck('role')
            ->contains(fn (mixed $role): bool => RoleCapabilityMap::hasCapability((string) $role, Capabilities::TENANT_MANAGE));
    }

    private static function userCanDeleteAnyTenant(User $user): bool
    {
        return $user->tenantMemberships()
            ->pluck('role')
            ->contains(fn (mixed $role): bool => RoleCapabilityMap::hasCapability((string) $role, Capabilities::TENANT_DELETE));
    }

    public static function form(Schema $schema): Schema
    {
        // ... [Schema Omitted - No Change] ...
        return $schema
            ->schema([
                Forms\Components\TextInput::make('name')
                    ->required()
                    ->maxLength(255),
                Forms\Components\Select::make('environment')
                    ->options([
                        'prod' => 'PROD',
                        'dev' => 'DEV',
                        'staging' => 'STAGING',
                        'other' => 'Other',
                    ])
                    ->default('other')
                    ->required(),
                Forms\Components\TextInput::make('tenant_id')
                    ->label('Tenant ID (GUID)')
                    ->required()
                    ->maxLength(255)
                    ->unique(ignoreRecord: true),
                Forms\Components\TextInput::make('domain')
                    ->label('Primary domain')
                    ->maxLength(255)
                    ->helperText('Credentials are managed in Provider connections.'),
            ]);
    }

    public static function getEloquentQuery(): Builder
    {
        // ... [Query Omitted - No Change] ...
        $user = auth()->user();

        if (! $user instanceof User) {
            return parent::getEloquentQuery()->whereRaw('1 = 0');
        }

        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        if ($workspaceId === null) {
            return parent::getEloquentQuery()->whereRaw('1 = 0');
        }

        $tenantIds = $user->tenants()
            ->withTrashed()
            ->where('workspace_id', $workspaceId)
            ->pluck('tenants.id');

        return parent::getEloquentQuery()
            ->withTrashed()
            ->whereIn('id', $tenantIds)
            ->withCount('policies')
            ->withMax('policies as last_policy_sync_at', 'last_synced_at');
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('name')
            ->paginated(TablePaginationProfiles::resource())
            ->persistFiltersInSession()
            ->persistSearchInSession()
            ->persistSortInSession()
            ->columns([
                Tables\Columns\TextColumn::make('name')
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('tenant_id')
                    ->label('Tenant ID')
                    ->copyable()
                    ->searchable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('environment')
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::TenantEnvironment))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::TenantEnvironment))
                    ->sortable(),
                Tables\Columns\TextColumn::make('policies_count')
                    ->label('Policies')
                    ->numeric()
                    ->sortable(),
                Tables\Columns\TextColumn::make('last_policy_sync_at')
                    ->label('Last Sync')
                    ->since()
                    ->sortable(),
                Tables\Columns\TextColumn::make('domain')
                    ->copyable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\IconColumn::make('is_current')
                    ->label('Current')
                    ->boolean(),
                Tables\Columns\TextColumn::make('status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::TenantStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::TenantStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantStatus))
                    ->sortable(),
                Tables\Columns\TextColumn::make('app_status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantAppStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::TenantAppStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::TenantAppStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantAppStatus)),
                Tables\Columns\TextColumn::make('created_at')
                    ->dateTime()
                    ->since()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                Tables\Filters\TrashedFilter::make()
                    ->label('Archived')
                    ->placeholder('Active')
                    ->trueLabel('All')
                    ->falseLabel('Archived')
                    ->default(true),
                Tables\Filters\SelectFilter::make('environment')
                    ->options([
                        'prod' => 'PROD',
                        'dev' => 'DEV',
                        'staging' => 'STAGING',
                        'other' => 'Other',
                    ]),
                Tables\Filters\SelectFilter::make('app_status')
                    ->options([
                        'ok' => 'OK',
                        'consent_required' => 'Consent required',
                        'error' => 'Error',
                        'unknown' => 'Unknown',
                    ]),
            ])
            ->actions([
                ActionGroup::make([
                    Actions\Action::make('view')
                        ->label('View')
                        ->icon('heroicon-o-eye')
                        ->url(fn (Tenant $record) => static::getUrl('view', ['record' => $record])),
                    UiEnforcement::forAction(
                        Actions\Action::make('syncTenant')
                            ->label('Sync')
                            ->icon('heroicon-o-arrow-path')
                            ->color('warning')
                            ->requiresConfirmation()
                            ->visible(function (Tenant $record): bool {
                                if (! $record->isActive()) {
                                    return false;
                                }

                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    return false;
                                }

                                return $user->canAccessTenant($record);
                            })
                            ->action(function (Tenant $record, AuditLogger $auditLogger, \Filament\Tables\Contracts\HasTable $livewire): void {
                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    abort(403);
                                }

                                if (! $user->canAccessTenant($record)) {
                                    abort(404);
                                }

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->can($user, $record, Capabilities::TENANT_SYNC)) {
                                    abort(403);
                                }

                                /** @var OperationRunService $opService */
                                $opService = app(OperationRunService::class);

                                $supportedTypes = config('tenantpilot.supported_policy_types', []);
                                $typeNames = array_map(
                                    static fn (array $typeConfig): string => (string) $typeConfig['type'],
                                    $supportedTypes,
                                );
                                sort($typeNames);

                                $inputs = [
                                    'scope' => 'full',
                                    'types' => $typeNames,
                                ];

                                $opRun = $opService->ensureRun(
                                    tenant: $record,
                                    type: 'policy.sync',
                                    inputs: $inputs,
                                    initiator: auth()->user()
                                );

                                if (! $opRun->wasRecentlyCreated && $opService->isStaleQueuedRun($opRun)) {
                                    $opService->failStaleQueuedRun(
                                        $opRun,
                                        message: 'Run was queued but never started (likely a previous dispatch error). Re-queuing.'
                                    );

                                    $opRun = $opService->ensureRun(
                                        tenant: $record,
                                        type: 'policy.sync',
                                        inputs: $inputs,
                                        initiator: auth()->user()
                                    );
                                }

                                if (! $opRun->wasRecentlyCreated && in_array($opRun->status, ['queued', 'running'], true)) {
                                    OpsUxBrowserEvents::dispatchRunEnqueued($livewire);
                                    OperationUxPresenter::alreadyQueuedToast((string) $opRun->type)
                                        ->actions([
                                            Actions\Action::make('view_run')
                                                ->label('View Run')
                                                ->url(OperationRunLinks::view($opRun, $record)),
                                        ])
                                        ->send();

                                    return;
                                }

                                $opService->dispatchOrFail($opRun, function () use ($record, $supportedTypes, $opRun): void {
                                    SyncPoliciesJob::dispatch((int) $record->getKey(), $supportedTypes, null, $opRun);
                                });

                                $auditLogger->log(
                                    tenant: $record,
                                    action: 'tenant.sync_dispatched',
                                    resourceType: 'tenant',
                                    resourceId: (string) $record->id,
                                    status: 'success',
                                    context: ['metadata' => ['tenant_id' => $record->tenant_id]],
                                );

                                OpsUxBrowserEvents::dispatchRunEnqueued($livewire);
                                OperationUxPresenter::queuedToast((string) $opRun->type)
                                    ->actions([
                                        Actions\Action::make('view_run')
                                            ->label('View Run')
                                            ->url(OperationRunLinks::view($opRun, $record)),
                                    ])
                                    ->send();
                            })
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::TENANT_SYNC)
                        ->apply(),
                    Actions\Action::make('openTenant')
                        ->label('Open')
                        ->icon('heroicon-o-arrow-right')
                        ->color('primary')
                        ->url(fn (Tenant $record) => \App\Filament\Resources\PolicyResource::getUrl('index', panel: 'tenant', tenant: $record))
                        ->visible(fn (Tenant $record) => $record->isActive()),
                    UiEnforcement::forAction(
                        Actions\Action::make('edit')
                            ->label('Edit')
                            ->icon('heroicon-o-pencil-square')
                            ->url(fn (Tenant $record) => static::getUrl('edit', ['record' => $record]))
                    )
                        ->requireCapability(Capabilities::TENANT_MANAGE)
                        ->apply(),
                    UiEnforcement::forAction(
                        Actions\Action::make('restore')
                            ->label('Restore')
                            ->color('success')
                            ->icon('heroicon-o-arrow-uturn-left')
                            ->successNotificationTitle('Tenant reactivated')
                            ->requiresConfirmation()
                            ->visible(fn (Tenant $record): bool => $record->trashed())
                            ->action(function (Tenant $record, AuditLogger $auditLogger): void {
                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    abort(403);
                                }

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->can($user, $record, Capabilities::TENANT_DELETE)) {
                                    abort(403);
                                }

                                $record->restore();

                                $auditLogger->log(
                                    tenant: $record,
                                    action: 'tenant.restored',
                                    resourceType: 'tenant',
                                    resourceId: (string) $record->id,
                                    status: 'success',
                                    context: ['metadata' => ['tenant_id' => $record->tenant_id]]
                                );
                            })
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::TENANT_DELETE)
                        ->apply(),
                    UiEnforcement::forAction(
                        Actions\Action::make('admin_consent')
                            ->label('Admin consent')
                            ->icon('heroicon-o-clipboard-document')
                            ->url(fn (Tenant $record) => static::adminConsentUrl($record))
                            ->visible(fn (Tenant $record) => static::adminConsentUrl($record) !== null)
                            ->openUrlInNewTab(),
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::TENANT_MANAGE)
                        ->apply(),
                    Actions\Action::make('open_in_entra')
                        ->label('Open in Entra')
                        ->icon('heroicon-o-arrow-top-right-on-square')
                        ->url(fn (Tenant $record) => static::entraUrl($record))
                        ->visible(fn (Tenant $record) => static::entraUrl($record) !== null)
                        ->openUrlInNewTab(),
                    UiEnforcement::forAction(
                        Actions\Action::make('verify')
                            ->label('Verify configuration')
                            ->icon('heroicon-o-check-badge')
                            ->color('primary')
                            ->requiresConfirmation()
                            ->visible(fn (Tenant $record): bool => $record->isActive())
                            ->action(function (
                                Tenant $record,
                                StartVerification $verification,
                                \Filament\Tables\Contracts\HasTable $livewire,
                            ): void {
                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    abort(403);
                                }

                                if (! $user->canAccessTenant($record)) {
                                    abort(404);
                                }

                                $result = $verification->providerConnectionCheckForTenant(
                                    tenant: $record,
                                    initiator: $user,
                                    extraContext: [
                                        'surface' => [
                                            'kind' => 'tenant_list_row',
                                        ],
                                    ],
                                );

                                $runUrl = OperationRunLinks::tenantlessView($result->run);

                                if ($result->status === 'scope_busy') {
                                    OpsUxBrowserEvents::dispatchRunEnqueued($livewire);

                                    Notification::make()
                                        ->title('Another operation is already running')
                                        ->body('Please wait for the active run to finish.')
                                        ->warning()
                                        ->actions([
                                            Actions\Action::make('view_run')
                                                ->label('View run')
                                                ->url($runUrl),
                                        ])
                                        ->send();

                                    return;
                                }

                                if ($result->status === 'deduped') {
                                    OpsUxBrowserEvents::dispatchRunEnqueued($livewire);

                                    OperationUxPresenter::alreadyQueuedToast((string) $result->run->type)
                                        ->actions([
                                            Actions\Action::make('view_run')
                                                ->label('View run')
                                                ->url($runUrl),
                                        ])
                                        ->send();

                                    return;
                                }

                                if ($result->status === 'blocked') {
                                    $reasonCode = is_string($result->run->context['reason_code'] ?? null)
                                        ? (string) $result->run->context['reason_code']
                                        : 'unknown_error';

                                    $actions = [
                                        Actions\Action::make('view_run')
                                            ->label('View run')
                                            ->url($runUrl),
                                    ];

                                    $nextSteps = $result->run->context['next_steps'] ?? [];
                                    $nextSteps = is_array($nextSteps) ? $nextSteps : [];

                                    foreach ($nextSteps as $index => $step) {
                                        if (! is_array($step)) {
                                            continue;
                                        }

                                        $label = is_string($step['label'] ?? null) ? trim((string) $step['label']) : '';
                                        $url = is_string($step['url'] ?? null) ? trim((string) $step['url']) : '';

                                        if ($label === '' || $url === '') {
                                            continue;
                                        }

                                        $actions[] = Actions\Action::make('next_step_'.$index)
                                            ->label($label)
                                            ->url($url);

                                        break;
                                    }

                                    Notification::make()
                                        ->title('Verification blocked')
                                        ->body("Blocked by provider configuration ({$reasonCode}).")
                                        ->warning()
                                        ->actions($actions)
                                        ->send();

                                    return;
                                }

                                OpsUxBrowserEvents::dispatchRunEnqueued($livewire);

                                OperationUxPresenter::queuedToast((string) $result->run->type)
                                    ->actions([
                                        Actions\Action::make('view_run')
                                            ->label('View run')
                                            ->url($runUrl),
                                    ])
                                    ->send();
                            }),
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::PROVIDER_RUN)
                        ->apply(),
                    static::rbacAction(),
                    UiEnforcement::forAction(
                        Actions\Action::make('archive')
                            ->label('Deactivate')
                            ->color('danger')
                            ->icon('heroicon-o-archive-box-x-mark')
                            ->requiresConfirmation()
                            ->visible(fn (Tenant $record): bool => ! $record->trashed())
                            ->action(function (Tenant $record, AuditLogger $auditLogger): void {
                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    abort(403);
                                }

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->can($user, $record, Capabilities::TENANT_DELETE)) {
                                    abort(403);
                                }

                                $record->delete();

                                $auditLogger->log(
                                    tenant: $record,
                                    action: 'tenant.archived',
                                    resourceType: 'tenant',
                                    resourceId: (string) $record->id,
                                    status: 'success',
                                    context: ['metadata' => ['tenant_id' => $record->tenant_id]]
                                );

                                Notification::make()
                                    ->title('Tenant deactivated')
                                    ->body('The tenant has been archived and hidden from lists.')
                                    ->success()
                                    ->send();
                            }),
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::TENANT_DELETE)
                        ->apply(),
                    UiEnforcement::forAction(
                        Actions\Action::make('forceDelete')
                            ->label('Force delete')
                            ->color('danger')
                            ->icon('heroicon-o-trash')
                            ->requiresConfirmation()
                            ->visible(fn (?Tenant $record): bool => (bool) $record?->trashed())
                            ->action(function (?Tenant $record, AuditLogger $auditLogger): void {
                                if ($record === null) {
                                    return;
                                }

                                $user = auth()->user();

                                if (! $user instanceof User) {
                                    abort(403);
                                }

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->can($user, $record, Capabilities::TENANT_DELETE)) {
                                    abort(403);
                                }

                                $tenant = Tenant::withTrashed()->find($record->id);

                                if (! $tenant?->trashed()) {
                                    Notification::make()
                                        ->title('Tenant must be archived first')
                                        ->danger()
                                        ->send();

                                    return;
                                }

                                $auditLogger->log(
                                    tenant: $tenant,
                                    action: 'tenant.force_deleted',
                                    resourceType: 'tenant',
                                    resourceId: (string) $tenant->id,
                                    status: 'success',
                                    context: ['metadata' => ['tenant_id' => $tenant->tenant_id]]
                                );

                                $tenant->forceDelete();

                                Notification::make()
                                    ->title('Tenant permanently deleted')
                                    ->success()
                                    ->send();
                            }),
                    )
                        ->preserveVisibility()
                        ->requireCapability(Capabilities::TENANT_DELETE)
                        ->apply(),
                ])
                    ->label('More')
                    ->icon('heroicon-o-ellipsis-vertical')
                    ->color('gray'),
            ])
            ->bulkActions([
                BulkActionGroup::make([
                    Actions\BulkAction::make('syncSelected')
                        ->label('Sync selected')
                        ->icon('heroicon-o-arrow-path')
                        ->color('warning')
                        ->requiresConfirmation()
                        ->visible(fn (): bool => auth()->user() instanceof User)
                        ->authorize(fn (): bool => auth()->user() instanceof User)
                        ->disabled(function (Collection $records): bool {
                            $user = auth()->user();

                            if (! $user instanceof User) {
                                return true;
                            }

                            if ($records->isEmpty()) {
                                return true;
                            }

                            /** @var CapabilityResolver $resolver */
                            $resolver = app(CapabilityResolver::class);

                            return $records
                                ->filter(fn ($record) => $record instanceof Tenant)
                                ->contains(fn (Tenant $tenant): bool => ! $resolver->can($user, $tenant, Capabilities::TENANT_SYNC));
                        })
                        ->tooltip(function (Collection $records): ?string {
                            $user = auth()->user();

                            if (! $user instanceof User) {
                                return UiTooltips::insufficientPermission();
                            }

                            if ($records->isEmpty()) {
                                return null;
                            }

                            /** @var CapabilityResolver $resolver */
                            $resolver = app(CapabilityResolver::class);

                            $isDenied = $records
                                ->filter(fn ($record) => $record instanceof Tenant)
                                ->contains(fn (Tenant $tenant): bool => ! $resolver->can($user, $tenant, Capabilities::TENANT_SYNC));

                            return $isDenied ? UiTooltips::insufficientPermission() : null;
                        })
                        ->action(function (Collection $records, AuditLogger $auditLogger): void {
                            $user = auth()->user();

                            if (! $user instanceof User) {
                                return;
                            }

                            /** @var CapabilityResolver $resolver */
                            $resolver = app(CapabilityResolver::class);

                            $eligible = $records
                                ->filter(fn ($record) => $record instanceof Tenant && $record->isActive())
                                ->filter(fn (Tenant $tenant) => $resolver->can($user, $tenant, Capabilities::TENANT_SYNC));

                            if ($eligible->isEmpty()) {
                                Notification::make()
                                    ->title('Bulk sync skipped')
                                    ->body('No eligible tenants selected.')
                                    ->icon('heroicon-o-information-circle')
                                    ->info()
                                    ->send();

                                return;
                            }

                            $tenantContext = Tenant::current() ?? $eligible->first();

                            if (! $tenantContext) {
                                return;
                            }

                            $ids = $eligible->pluck('id')->toArray();
                            $count = $eligible->count();

                            /** @var BulkSelectionIdentity $selection */
                            $selection = app(BulkSelectionIdentity::class);
                            $selectionIdentity = $selection->fromIds($ids);

                            /** @var OperationRunService $runs */
                            $runs = app(OperationRunService::class);

                            $opRun = $runs->enqueueBulkOperation(
                                tenant: $tenantContext,
                                type: 'tenant.sync',
                                targetScope: [
                                    'entra_tenant_id' => (string) ($tenantContext->tenant_id ?? $tenantContext->external_id),
                                ],
                                selectionIdentity: $selectionIdentity,
                                dispatcher: function ($operationRun) use ($tenantContext, $user, $ids): void {
                                    BulkTenantSyncJob::dispatch(
                                        tenantId: (int) $tenantContext->getKey(),
                                        userId: (int) $user->getKey(),
                                        tenantIds: $ids,
                                        operationRun: $operationRun,
                                    );
                                },
                                initiator: $user,
                                extraContext: [
                                    'tenant_count' => $count,
                                ],
                                emitQueuedNotification: false,
                            );

                            OperationUxPresenter::queuedToast('tenant.sync')
                                ->actions([
                                    Actions\Action::make('view_run')
                                        ->label('View run')
                                        ->url(OperationRunLinks::view($opRun, $tenantContext)),
                                ])
                                ->send();
                        })
                        ->deselectRecordsAfterCompletion(),
                ])->label('More'),
            ])
            ->headerActions([])
            ->emptyStateHeading('No tenants connected')
            ->emptyStateDescription('Add a tenant to start syncing inventory, policies, and provider health into this workspace.')
            ->emptyStateIcon('heroicon-o-building-office-2');
    }

    public static function infolist(Schema $schema): Schema
    {
        // ... [Infolist Omitted - No Change] ...
        return $schema
            ->schema([
                Section::make('Identity')
                    ->schema([
                        Infolists\Components\TextEntry::make('name'),
                        Infolists\Components\TextEntry::make('tenant_id')->label('Tenant ID')->copyable(),
                        Infolists\Components\TextEntry::make('domain')->copyable(),
                        Infolists\Components\TextEntry::make('status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::TenantStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::TenantStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantStatus)),
                        Infolists\Components\TextEntry::make('app_status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantAppStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::TenantAppStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::TenantAppStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantAppStatus)),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),
                Section::make('Provider')
                    ->schema([
                        Infolists\Components\ViewEntry::make('provider_connection_state')
                            ->label('Provider connection')
                            ->state(fn (Tenant $record): array => static::providerConnectionState($record))
                            ->view('filament.infolists.entries.provider-connection-state')
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
                Section::make('RBAC')
                    ->schema([
                        Infolists\Components\TextEntry::make('rbac_not_configured_hint')
                            ->label('Status')
                            ->state('Not configured — Intune RBAC has not been set up for this tenant. Write operations will be blocked.')
                            ->icon('heroicon-o-shield-exclamation')
                            ->color('warning')
                            ->columnSpanFull()
                            ->visible(fn (Tenant $record): bool => blank($record->rbac_status)),
                        Infolists\Components\TextEntry::make('rbac_status')
                            ->label('RBAC status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantRbacStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::TenantRbacStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::TenantRbacStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantRbacStatus))
                            ->visible(fn (Tenant $record): bool => filled($record->rbac_status)),
                        Infolists\Components\TextEntry::make('rbac_explanation')
                            ->label('Summary')
                            ->state(function (Tenant $record): string {
                                $status = $record->rbac_status;
                                $lastChecked = $record->rbac_last_checked_at;
                                $threshold = (int) config('tenantpilot.hardening.intune_write_gate.freshness_threshold_hours', 24);

                                if (blank($status) || $status === 'not_configured') {
                                    return 'RBAC is not configured. Write operations to this tenant are blocked until RBAC is set up.';
                                }

                                if (in_array($status, ['degraded', 'failed', 'error', 'missing', 'partial'], true)) {
                                    return 'RBAC health check reported an unhealthy state. Write operations are blocked.';
                                }

                                if ($status === 'ok' && ($lastChecked === null || $lastChecked->diffInHours(now()) >= $threshold)) {
                                    return "RBAC status is OK but the last health check is older than {$threshold} hours. Write operations are blocked until refreshed.";
                                }

                                return 'RBAC is healthy and up to date. Write operations are permitted.';
                            })
                            ->columnSpanFull()
                            ->visible(fn (Tenant $record): bool => filled($record->rbac_status)),
                        Infolists\Components\TextEntry::make('rbac_last_checked_at')
                            ->label('Last checked')
                            ->since()
                            ->visible(fn (Tenant $record): bool => filled($record->rbac_status)),
                        Infolists\Components\TextEntry::make('rbac_role_display_name')
                            ->label('RBAC role')
                            ->visible(fn (Tenant $record): bool => filled($record->rbac_status)),
                        Section::make('RBAC Details')
                            ->schema([
                                Infolists\Components\TextEntry::make('rbac_status_reason')
                                    ->label('Reason'),
                                Infolists\Components\TextEntry::make('rbac_role_definition_id')
                                    ->label('Role definition ID')
                                    ->copyable(),
                                Infolists\Components\TextEntry::make('rbac_scope_mode')
                                    ->label('Scope'),
                                Infolists\Components\TextEntry::make('rbac_scope_id')
                                    ->label('Scope ID'),
                                Infolists\Components\TextEntry::make('rbac_group_id')
                                    ->label('Group ID')
                                    ->copyable(),
                                Infolists\Components\TextEntry::make('rbac_role_assignment_id')
                                    ->label('Role assignment ID')
                                    ->copyable(),
                                Infolists\Components\ViewEntry::make('rbac_summary')
                                    ->label('Last RBAC Setup')
                                    ->view('filament.infolists.entries.rbac-summary')
                                    ->visible(fn (Tenant $record) => filled($record->rbac_last_setup_at)),
                            ])
                            ->columns(2)
                            ->collapsible()
                            ->collapsed()
                            ->visible(fn (Tenant $record): bool => filled($record->rbac_status)),
                    ])
                    ->columns(2)
                    ->columnSpanFull()
                    ->collapsible(),
                Section::make('Integration')
                    ->schema([
                        Infolists\Components\TextEntry::make('admin_consent_url')
                            ->label('Admin consent URL')
                            ->state(fn (Tenant $record) => static::adminConsentUrl($record))
                            ->visible(fn (?string $state) => filled($state))
                            ->copyable()
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull()
                    ->collapsible(),
                Section::make('Metadata')
                    ->schema([
                        Infolists\Components\TextEntry::make('created_at')->dateTime(),
                        Infolists\Components\TextEntry::make('updated_at')->dateTime(),
                    ])
                    ->columns(2)
                    ->columnSpanFull()
                    ->collapsed(),
                Section::make('Required permissions')
                    ->schema([
                        Infolists\Components\RepeatableEntry::make('permissions')
                            ->label('')
                            ->state(fn (Tenant $record) => static::storedPermissionSnapshot($record))
                            ->schema([
                                Infolists\Components\TextEntry::make('key')->label('Permission')->badge(),
                                Infolists\Components\TextEntry::make('type')->badge(),
                                Infolists\Components\TextEntry::make('features')
                                    ->label('Features')
                                    ->formatStateUsing(fn ($state) => is_array($state) ? implode(', ', $state) : (string) $state),
                                Infolists\Components\TextEntry::make('status')
                                    ->badge()
                                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantPermissionStatus))
                                    ->color(BadgeRenderer::color(BadgeDomain::TenantPermissionStatus))
                                    ->icon(BadgeRenderer::icon(BadgeDomain::TenantPermissionStatus))
                                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantPermissionStatus)),
                            ])
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull()
                    ->collapsible(),
            ]);
    }

    /**
     * @return array<int, array{key:string,type:string,description:?string,features:array<int,string>,status:string,details:array<string,mixed>|null}>
     */
    protected static function storedPermissionSnapshot(Tenant $tenant): array
    {
        $required = config('intune_permissions.permissions', []);

        $stored = $tenant->permissions()
            ->get()
            ->keyBy('permission_key');

        $snapshot = [];

        foreach ($required as $permission) {
            $key = is_string($permission['key'] ?? null) ? (string) $permission['key'] : null;

            if ($key === null || $key === '') {
                continue;
            }

            $storedEntry = $stored->get($key);
            $storedDetails = $storedEntry?->details;

            $snapshot[] = [
                'key' => $key,
                'type' => is_string($permission['type'] ?? null) ? (string) $permission['type'] : 'application',
                'description' => is_string($permission['description'] ?? null) ? (string) $permission['description'] : null,
                'features' => is_array($permission['features'] ?? null) ? $permission['features'] : [],
                'status' => is_string($storedEntry?->status ?? null) ? (string) $storedEntry->status : 'missing',
                'details' => is_array($storedDetails) ? $storedDetails : null,
            ];
        }

        return $snapshot;
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListTenants::route('/'),
            'view' => Pages\ViewTenant::route('/{record}'),
            'edit' => Pages\EditTenant::route('/{record}/edit'),
            'memberships' => Pages\ManageTenantMemberships::route('/{record}/memberships'),
        ];
    }

    public static function getRelations(): array
    {
        return [
            RelationManagers\TenantMembershipsRelationManager::class,
        ];
    }

    /**
     * @param  array<mixed>  $parameters
     */
    public static function getUrl(?string $name = null, array $parameters = [], bool $isAbsolute = true, ?string $panel = null, ?Model $tenant = null, bool $shouldGuessMissingParameters = false): string
    {
        $panel ??= 'admin';

        return parent::getUrl($name, $parameters, $isAbsolute, $panel, $tenant, $shouldGuessMissingParameters);
    }

    public static function rbacAction(): Actions\Action
    {
        // ... [RBAC Action Omitted - No Change] ...
        return Actions\Action::make('setup_rbac')
            ->label('Setup Intune RBAC')
            ->icon('heroicon-o-shield-check')
            ->color('primary')
            ->form([
                Forms\Components\Select::make('role_definition_id')
                    ->label('RBAC role')
                    ->required()
                    ->searchable()
                    ->optionsLimit(20)
                    ->searchDebounce(400)
                    ->getSearchResultsUsing(fn (string $search, ?Tenant $record) => static::roleSearchOptions($record, $search))
                    ->getOptionLabelUsing(fn (?string $value, ?Tenant $record) => static::roleLabelFromCache($record, $value))
                    ->helperText(fn (?Tenant $record) => static::roleSearchHelper($record))
                    ->hintAction(fn (?Tenant $record) => static::syncRoleDefinitionsAction())
                    ->hint('Wizard grants Intune RBAC roles only. "Intune Administrator" is an Entra directory role and is not assigned here.')
                    ->noSearchResultsMessage('No Intune RBAC roleDefinitions found (tenant may restrict RBAC or missing permission).')
                    ->loadingMessage('Loading roles...')
                    ->afterStateUpdated(function (Set $set, ?string $state, ?Tenant $record) {
                        $set('role_display_name', static::roleNameFromCache($record, $state));
                    }),
                Forms\Components\Hidden::make('role_display_name')
                    ->dehydrated(),
                Forms\Components\Select::make('scope')
                    ->label('Scope')
                    ->required()
                    ->options([
                        'all_devices' => 'All devices (global)',
                        'scope_group' => 'Scope group (enter ID)',
                    ])
                    ->default('all_devices')
                    ->live(),
                Forms\Components\Select::make('scope_group_id')
                    ->label('Scope group')
                    ->searchable()
                    ->searchPrompt('Type at least 2 characters')
                    ->optionsLimit(20)
                    ->searchDebounce(400)
                    ->placeholder('Search security groups')
                    ->visible(fn (Get $get) => $get('scope') === 'scope_group')
                    ->required(fn (Get $get) => $get('scope') === 'scope_group')
                    ->disabled(fn (?Tenant $record): bool => static::delegatedToken($record) === null)
                    ->getSearchResultsUsing(fn (string $search, ?Tenant $record) => static::groupSearchOptions($record, $search))
                    ->getOptionLabelUsing(fn (?string $value, ?Tenant $record) => static::groupLabelFromCache($record, $value))
                    ->noSearchResultsMessage('No security groups found')
                    ->loadingMessage('Searching groups...'),
                Forms\Components\Select::make('group_mode')
                    ->label('Group mode')
                    ->required()
                    ->options([
                        'create' => 'Create new security group',
                        'existing' => 'Use existing security group',
                    ])
                    ->default('create')
                    ->live(),
                Forms\Components\TextInput::make('group_name')
                    ->label('Group name')
                    ->default('TenantPilot-Intune-RBAC')
                    ->visible(fn (callable $get) => $get('group_mode') === 'create'),
                Forms\Components\Select::make('existing_group_id')
                    ->label('Security group')
                    ->searchable()
                    ->searchPrompt('Type at least 2 characters')
                    ->optionsLimit(20)
                    ->searchDebounce(400)
                    ->placeholder('Search security groups')
                    ->visible(fn (Get $get) => $get('group_mode') === 'existing')
                    ->required(fn (Get $get) => $get('group_mode') === 'existing')
                    ->disabled(fn (?Tenant $record): bool => static::delegatedToken($record) === null)
                    ->getSearchResultsUsing(fn (string $search, ?Tenant $record) => static::groupSearchOptions($record, $search))
                    ->getOptionLabelUsing(fn (?string $value, ?Tenant $record) => static::groupLabelFromCache($record, $value))
                    ->noSearchResultsMessage('No security groups found')
                    ->loadingMessage('Searching groups...'),
            ])
            ->visible(fn (Tenant $record): bool => $record->isActive())
            ->disabled(function (Tenant $record): bool {
                $user = auth()->user();

                if (! $user instanceof User) {
                    return true;
                }

                /** @var CapabilityResolver $resolver */
                $resolver = app(CapabilityResolver::class);

                return ! $resolver->can($user, $record, Capabilities::TENANT_MANAGE);
            })
            ->requiresConfirmation()
            ->action(function (
                array $data,
                Tenant $record,
                RbacOnboardingService $service,
                AuditLogger $auditLogger
            ) {
                $user = auth()->user();

                if (! $user instanceof User) {
                    abort(403);
                }

                /** @var CapabilityResolver $resolver */
                $resolver = app(CapabilityResolver::class);

                if (! $resolver->can($user, $record, Capabilities::TENANT_MANAGE)) {
                    abort(403);
                }

                $userCacheKey = RbacDelegatedAuthController::cacheKey($record, auth()->id(), null);
                $sessionCacheKey = RbacDelegatedAuthController::cacheKey($record, auth()->id(), session()->getId());

                $token = Cache::get($sessionCacheKey) ?? Cache::get($userCacheKey);

                if (! $token) {
                    Notification::make()
                        ->title('Login to grant RBAC')
                        ->body('Delegated login required to continue.')
                        ->actions([
                            Actions\Action::make('open_rbac_login')
                                ->label('Open RBAC login')
                                ->url(route('admin.rbac.start', [
                                    'tenant' => $record->graphTenantId(),
                                    'return' => route('filament.admin.resources.tenants.view', [
                                        'record' => $record,
                                    ]),
                                ])),
                        ])
                        ->warning()
                        ->persistent()
                        ->send();

                    return;
                }

                $result = $service->run($record, $data, $user, $token);

                Cache::forget($sessionCacheKey);
                Cache::forget($userCacheKey);

                if ($result['status'] === 'success') {
                    Notification::make()
                        ->title('RBAC setup completed')
                        ->body(sprintf(
                            'Role: %s | Scope: %s | Group: %s | Assignment: %s',
                            $data['role_display_name'] ?? $data['role_definition_id'] ?? 'n/a',
                            $data['scope'] ?? 'n/a',
                            $result['group_id'] ?? 'n/a',
                            $result['role_assignment_id'] ?? 'n/a'
                        ))
                        ->success()
                        ->send();

                    if (($data['scope'] ?? null) === 'scope_group') {
                        Notification::make()
                            ->title('Scope-limited selection')
                            ->body('RBAC scope is limited to a scope group; inventory/restore may be partial.')
                            ->warning()
                            ->send();
                    }

                    if (config('tenantpilot.features.conditional_access', false) === false) {
                        Notification::make()
                            ->title('CA canary disabled')
                            ->body('Conditional Access canary is disabled by feature flag.')
                            ->warning()
                            ->send();
                    }

                    return;
                }

                $auditLogger->log(
                    tenant: $record,
                    action: 'rbac.setup.failed',
                    resourceType: 'tenant',
                    resourceId: (string) $record->id,
                    status: 'error',
                    context: ['metadata' => ['error' => $result['message'] ?? 'unknown']],
                );

                Notification::make()
                    ->title('RBAC setup failed')
                    ->body($result['message'] ?? 'Unknown error')
                    ->danger()
                    ->send();
            });
    }

    public static function adminConsentUrl(Tenant $tenant): ?string
    {
        $tenantId = $tenant->graphTenantId();
        $clientId = $tenant->app_client_id;

        if (! is_string($clientId) || trim($clientId) === '') {
            $clientId = static::resolveProviderClientIdForConsent($tenant);
        }
        $redirectUri = route('admin.consent.callback');
        $state = sprintf('tenantpilot|%s', $tenant->id);

        if (! $tenantId || ! $clientId || ! $redirectUri) {
            return null;
        }

        // Admin consent should use `.default` so the tenant consents to the app's configured
        // application permissions. Keeping the URL short also avoids edge cases where a long
        // scope string gets truncated and causes AADSTS900144 (missing `scope`).
        $scopes = 'https://graph.microsoft.com/.default';

        $query = http_build_query([
            'client_id' => $clientId,
            'state' => $state,
            'redirect_uri' => $redirectUri,
            'scope' => $scopes,
        ]);

        return sprintf('https://login.microsoftonline.com/%s/v2.0/adminconsent?%s', $tenantId, $query);
    }

    private static function resolveProviderClientIdForConsent(Tenant $tenant): ?string
    {
        $connection = ProviderConnection::query()
            ->where('tenant_id', (int) $tenant->getKey())
            ->where('provider', 'microsoft')
            ->orderByDesc('is_default')
            ->orderBy('id')
            ->first();

        if (! $connection instanceof ProviderConnection) {
            return null;
        }

        $payload = $connection->credential?->payload;

        if (! is_array($payload)) {
            return null;
        }

        $clientId = $payload['client_id'] ?? null;

        if (! is_string($clientId)) {
            return null;
        }

        $clientId = trim($clientId);

        return $clientId !== '' ? $clientId : null;
    }

    /**
     * @return array{
     *   state:string,
     *   cta_url:string,
     *   display_name:?string,
     *   provider:?string,
     *   status:?string,
     *   health_status:?string,
     *   last_health_check_at:?string,
     *   last_error_reason_code:?string
     * }
     */
    private static function providerConnectionState(Tenant $tenant): array
    {
        $ctaUrl = ProviderConnectionResource::getUrl('index', ['tenant_id' => (string) $tenant->external_id], panel: 'admin');

        $connection = ProviderConnection::query()
            ->where('tenant_id', (int) $tenant->getKey())
            ->where('provider', 'microsoft')
            ->orderByDesc('is_default')
            ->orderBy('id')
            ->first();

        if (! $connection instanceof ProviderConnection) {
            return [
                'state' => 'needs_action',
                'cta_url' => $ctaUrl,
                'display_name' => null,
                'provider' => null,
                'status' => null,
                'health_status' => null,
                'last_health_check_at' => null,
                'last_error_reason_code' => null,
            ];
        }

        return [
            'state' => $connection->is_default ? 'default_configured' : 'configured',
            'cta_url' => $ctaUrl,
            'display_name' => (string) $connection->display_name,
            'provider' => (string) $connection->provider,
            'status' => is_string($connection->status) ? $connection->status : null,
            'health_status' => is_string($connection->health_status) ? $connection->health_status : null,
            'last_health_check_at' => optional($connection->last_health_check_at)->toDateTimeString(),
            'last_error_reason_code' => is_string($connection->last_error_reason_code) ? $connection->last_error_reason_code : null,
        ];
    }

    public static function entraUrl(Tenant $tenant): ?string
    {
        if ($tenant->app_client_id) {
            return sprintf(
                'https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/%s',
                $tenant->app_client_id
            );
        }

        if ($tenant->graphTenantId()) {
            return sprintf(
                'https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview/tenantId/%s',
                $tenant->graphTenantId()
            );
        }

        return null;
    }

    private static function delegatedToken(?Tenant $tenant): ?string
    {
        if (! $tenant) {
            return null;
        }

        $userKey = RbacDelegatedAuthController::cacheKey($tenant, auth()->id(), null);
        $sessionKey = RbacDelegatedAuthController::cacheKey($tenant, auth()->id(), session()->getId());

        return Cache::get($userKey) ?? Cache::get($sessionKey);
    }

    private static function loginToSearchRolesAction(?Tenant $tenant): ?Actions\Action
    {
        return null;
    }

    public static function roleSearchHelper(?Tenant $tenant): ?string
    {
        if (! $tenant) {
            return null;
        }

        return static::delegatedToken($tenant) === null ? 'Login to search roles' : null;
    }

    /**
     * @return array<string, string>
     */
    public static function roleSearchOptions(?Tenant $tenant, string $search): array
    {
        $token = static::delegatedToken($tenant);

        if ($token !== null) {
            return static::searchRoleDefinitionsDelegated($tenant, $search, $token);
        }

        return static::searchRoleDefinitions($tenant, $search);
    }

    /**
     * @return array<string, string>
     */
    private static function searchRoleDefinitionsDelegated(?Tenant $tenant, string $search, string $token): array
    {
        if (! $tenant || mb_strlen($search) < 2) {
            return [];
        }

        $needle = mb_strtolower($search);

        /** @var GraphClientInterface $graph */
        $graph = app(GraphClientInterface::class);

        $response = $graph->request('GET', 'deviceManagement/roleDefinitions', [
            'access_token' => $token,
        ]);

        if ($response->failed()) {
            return [];
        }

        $roles = is_array($response->data['value'] ?? null) ? $response->data['value'] : [];

        $results = [];

        foreach ($roles as $role) {
            $id = is_string($role['id'] ?? null) ? (string) $role['id'] : null;
            $displayName = is_string($role['displayName'] ?? null) ? (string) $role['displayName'] : null;

            if (! $id || ! $displayName) {
                continue;
            }

            if (! str_contains(mb_strtolower($displayName), $needle)) {
                continue;
            }

            $results[$id] = static::formatRoleLabel($displayName, $id);
        }

        ksort($results);

        return array_slice($results, 0, 20, true);
    }

    /**
     * @return array<string, string>
     */
    private static function searchRoleDefinitions(?Tenant $tenant, string $search): array
    {
        if (! $tenant || mb_strlen($search) < 2) {
            return [];
        }

        $needle = mb_strtolower($search);

        return EntraRoleDefinition::query()
            ->where('tenant_id', $tenant->getKey())
            ->whereRaw('lower(display_name) like ?', [$needle.'%'])
            ->orderBy('display_name')
            ->limit(20)
            ->get(['entra_id', 'display_name'])
            ->mapWithKeys(fn (EntraRoleDefinition $role): array => [
                (string) $role->entra_id => static::formatRoleLabel((string) $role->display_name, (string) $role->entra_id),
            ])
            ->all();
    }

    public static function roleLabelFromCache(?Tenant $tenant, ?string $roleId): ?string
    {
        if (! $tenant || blank($roleId)) {
            return $roleId;
        }

        $displayName = EntraRoleDefinition::query()
            ->where('tenant_id', $tenant->getKey())
            ->where('entra_id', $roleId)
            ->value('display_name');

        $displayName = is_string($displayName) && $displayName !== '' ? $displayName : $roleId;

        return static::formatRoleLabel($displayName, $roleId);
    }

    private static function roleNameFromCache(?Tenant $tenant, ?string $roleId): ?string
    {
        if (! $tenant || blank($roleId)) {
            return $roleId;
        }

        $displayName = EntraRoleDefinition::query()
            ->where('tenant_id', $tenant->getKey())
            ->where('entra_id', $roleId)
            ->value('display_name');

        return is_string($displayName) && $displayName !== '' ? $displayName : $roleId;
    }

    private static function formatRoleLabel(?string $displayName, string $id): string
    {
        $suffix = sprintf(' (%s)', Str::limit($id, 8, ''));

        return trim(($displayName ?: 'RBAC role').$suffix);
    }

    private static function loginToSearchGroupsAction(?Tenant $tenant): ?Actions\Action
    {
        return null;
    }

    public static function groupSearchHelper(?Tenant $tenant): ?string
    {
        if (! $tenant) {
            return null;
        }

        return static::delegatedToken($tenant) === null ? 'Login to search groups' : null;
    }

    /**
     * @return array<string, string>
     */
    public static function groupSearchOptions(?Tenant $tenant, string $search): array
    {
        if (! $tenant || mb_strlen($search) < 2) {
            return [];
        }

        $token = static::delegatedToken($tenant);

        if ($token !== null) {
            /** @var GraphClientInterface $graph */
            $graph = app(GraphClientInterface::class);

            $response = $graph->request('GET', 'groups', [
                'access_token' => $token,
                'query' => [
                    '$filter' => sprintf("startswith(displayName,'%s') and securityEnabled eq true", addslashes($search)),
                ],
            ]);

            if ($response->failed()) {
                return [];
            }

            $groups = is_array($response->data['value'] ?? null) ? $response->data['value'] : [];
            $results = [];

            foreach ($groups as $group) {
                $id = is_string($group['id'] ?? null) ? (string) $group['id'] : null;
                $displayName = is_string($group['displayName'] ?? null) ? (string) $group['displayName'] : null;

                if (! $id || ! $displayName) {
                    continue;
                }

                $results[$id] = EntraGroupLabelResolver::formatLabel($displayName, $id);
            }

            ksort($results);

            return array_slice($results, 0, 20, true);
        }

        $needle = mb_strtolower($search);

        return EntraGroup::query()
            ->where('tenant_id', $tenant->getKey())
            ->whereRaw('lower(display_name) like ?', [$needle.'%'])
            ->orderBy('display_name')
            ->limit(20)
            ->get(['entra_id', 'display_name'])
            ->mapWithKeys(fn (EntraGroup $group): array => [
                (string) $group->entra_id => EntraGroupLabelResolver::formatLabel((string) $group->display_name, (string) $group->entra_id),
            ])
            ->all();
    }

    public static function groupLabelFromCache(?Tenant $tenant, ?string $groupId): ?string
    {
        if (! $tenant || blank($groupId)) {
            return $groupId;
        }

        $resolver = app(EntraGroupLabelResolver::class);

        return $resolver->resolveOne($tenant, $groupId);
    }

    public static function syncRoleDefinitionsAction(): Actions\Action
    {
        return Actions\Action::make('sync_role_definitions')
            ->label('Sync now')
            ->icon('heroicon-o-arrow-path')
            ->color('warning')
            ->visible(fn (?Tenant $record): bool => $record instanceof Tenant && $record->isActive())
            ->action(function (Tenant $record, RoleDefinitionsSyncService $syncService): void {
                $user = auth()->user();

                if (! $user instanceof User) {
                    abort(403);
                }

                if (! $user->canAccessTenant($record)) {
                    abort(404);
                }

                /** @var CapabilityResolver $resolver */
                $resolver = app(CapabilityResolver::class);

                if (! $resolver->can($user, $record, Capabilities::TENANT_MANAGE)) {
                    abort(403);
                }

                $opRun = $syncService->startManualSync($record, $user);

                $runUrl = OperationRunLinks::tenantlessView($opRun);

                if (! $opRun->wasRecentlyCreated && in_array($opRun->status, ['queued', 'running'], true)) {
                    OperationUxPresenter::alreadyQueuedToast((string) $opRun->type)
                        ->actions([
                            Actions\Action::make('view_run')
                                ->label('View run')
                                ->url($runUrl),
                        ])
                        ->send();

                    return;
                }

                OperationUxPresenter::queuedToast('directory_role_definitions.sync')
                    ->actions([
                        Actions\Action::make('view_run')
                            ->label('View run')
                            ->url($runUrl),
                    ])
                    ->send();
            });
    }
}
