<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpSettlementPermissionAssignments;

use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\DberpSettlementPermissionAssignments\Pages\EditDberpSettlementPermissionAssignment;
use App\Filament\Resources\DberpSettlementPermissionAssignments\Pages\ListDberpSettlementPermissionAssignments;
use App\Models\User;
use App\Services\DberpPermissionRegistry;
use App\Services\DberpPermissionService;
use BackedEnum;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use UnitEnum;

class DberpSettlementPermissionAssignmentResource extends Resource
{
    use InteractsWithDberpPermissions;

    protected static ?string $model = User::class;

    protected static ?string $recordTitleAttribute = 'name';

    protected static ?int $navigationSort = 70;

    public static function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                Section::make(__('dberp.sections.settlement_permission'))
                    ->schema([
                        TextInput::make('name')
                            ->label(__('dberp.fields.user'))
                            ->disabled()
                            ->dehydrated(false),
                        TextInput::make('email')
                            ->label(__('dberp.fields.email'))
                            ->disabled()
                            ->dehydrated(false),
                    ])
                    ->columns(2),
                ...static::settlementPermissionSections(),
            ]);
    }

    /**
     * @return list<Section>
     */
    public static function settlementPermissionSections(): array
    {
        $registry = app(DberpPermissionRegistry::class);

        return collect(app(DberpPermissionRegistry::class)->groupedRecords())
            ->map(function (array $group, string $module) use ($registry): Section {
                $options = collect($group['permissions'])
                    ->mapWithKeys(fn (array $definition, string $code): array => [
                        $code => $registry->localizedDisplayName($code, $definition['display_name']),
                    ])
                    ->all();

                $descriptions = collect($group['permissions'])
                    ->mapWithKeys(function (array $definition, string $code): array {
                        $labelBase = trim((string) ($definition['display_name'] ?? ''));
                        $description = trim((string) ($definition['description'] ?? ''));

                        if ($description === '' || $description === $labelBase) {
                            return [$code => ''];
                        }

                        return [$code => $description];
                    })
                    ->all();

                $checkboxList = CheckboxList::make("settlement_permission_groups.{$module}")
                    ->label(__('dberp.fields.settlement_permissions'))
                    ->options($options)
                    ->columns(2)
                    ->gridDirection('row')
                    ->bulkToggleable()
                    ->columnSpanFull();

                if (collect($descriptions)->contains(fn (mixed $text): bool => is_string($text) && $text !== '')) {
                    $checkboxList->descriptions($descriptions);
                }

                return Section::make($group['label'])
                    ->heading($group['label'])
                    ->description(__('dberp.sections.settlement_permission_by_module'))
                    ->schema([
                        $checkboxList,
                    ])
                    ->collapsible();
            })
            ->values()
            ->all();
    }

    /**
     * @param  array<string, mixed>  $data
     * @return list<string>
     */
    public static function extractSettlementPermissionCodes(array $data): array
    {
        return collect((array) ($data['settlement_permission_groups'] ?? []))
            ->flatMap(fn (mixed $codes): array => array_values(array_filter((array) $codes)))
            ->map(fn (mixed $code): string => (string) $code)
            ->filter(fn (string $code): bool => $code !== '')
            ->unique()
            ->values()
            ->all();
    }

    /**
     * @param  list<string>  $permissionCodes
     * @return array<string, list<string>>
     */
    public static function settlementPermissionGroupsForForm(array $permissionCodes): array
    {
        return collect(app(DberpPermissionRegistry::class)->groupedRecords())
            ->mapWithKeys(function (array $group, string $module) use ($permissionCodes): array {
                return [
                    $module => array_values(array_intersect(array_keys($group['permissions']), $permissionCodes)),
                ];
            })
            ->all();
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('id')
            ->columns([
                TextColumn::make('name')
                    ->label(__('dberp.fields.user'))
                    ->searchable(),
                TextColumn::make('email')
                    ->label(__('dberp.fields.email'))
                    ->searchable(),
                TextColumn::make('effective_permission_count')
                    ->label(__('dberp.fields.permission_count'))
                    ->state(fn (User $record): int => count(app(DberpPermissionService::class)->grantedPermissionCodes($record))),
                TextColumn::make('updated_at')
                    ->label(__('dberp.fields.updated_at'))
                    ->dateTime(),
            ]);
    }

    public static function canViewAny(): bool
    {
        return static::allowsPermission(DberpPermissionService::MANAGE_SETTLEMENT_PERMISSIONS);
    }

    public static function canEdit(Model $record): bool
    {
        if (! static::allowsPermission(DberpPermissionService::MANAGE_SETTLEMENT_PERMISSIONS)) {
            return false;
        }

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

        return ! $record->isBootstrapInstallAdmin();
    }

    public static function canCreate(): bool
    {
        return false;
    }

    public static function canDelete(Model $record): bool
    {
        return false;
    }

    public static function getPages(): array
    {
        return [
            'index' => ListDberpSettlementPermissionAssignments::route('/'),
            'edit' => EditDberpSettlementPermissionAssignment::route('/{record}/edit'),
        ];
    }

    public static function getNavigationGroup(): string|UnitEnum|null
    {
        return __('dberp.nav.system');
    }

    public static function getNavigationIcon(): string|BackedEnum|Htmlable|null
    {
        return null;
    }

    public static function getModelLabel(): string
    {
        return __('dberp.resources.settlement_permission_assignment.label');
    }

    public static function getPluralModelLabel(): string
    {
        return __('dberp.resources.settlement_permission_assignment.plural');
    }
}
