<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpAdminUsers;

use App\Enums\AdminRoleStatus;
use App\Enums\AdminUserStatus;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\DberpAdminUsers\Pages\CreateDberpAdminUser;
use App\Filament\Resources\DberpAdminUsers\Pages\EditDberpAdminUser;
use App\Filament\Resources\DberpAdminUsers\Pages\ListDberpAdminUsers;
use App\Models\DberpAdminRole;
use App\Models\User;
use App\Services\DberpAdminAccessService;
use App\Services\DberpPermissionService;
use BackedEnum;
use DomainException;
use Filament\Actions\Action;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use UnitEnum;

class DberpAdminUserResource extends Resource
{
    use InteractsWithDberpPermissions;

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

    protected static ?string $recordTitleAttribute = 'name';

    protected static ?int $navigationSort = 50;

    public static function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                Section::make(__('dberp.sections.admin_user_basic'))
                    ->schema([
                        TextInput::make('name')
                            ->label(__('dberp.fields.admin_name'))
                            ->required()
                            ->maxLength(255),
                        TextInput::make('nickname')
                            ->label(__('dberp.fields.nickname'))
                            ->maxLength(80),
                        TextInput::make('login_account')
                            ->label(__('dberp.fields.login_account'))
                            ->required()
                            ->maxLength(64)
                            ->regex('/^[a-zA-Z0-9_.-]+$/')
                            ->unique(ignoreRecord: true)
                            ->helperText('仅支持字母、数字、下划线、连字符与英文句点，最长 64 位。'),
                        TextInput::make('email')
                            ->label(__('dberp.fields.email'))
                            ->email()
                            ->maxLength(255)
                            ->nullable(),
                        Select::make('status')
                            ->label(__('dberp.fields.status'))
                            ->options(AdminUserStatus::options())
                            ->default(AdminUserStatus::Enabled->value)
                            ->required(),
                    ])
                    ->columns(2),
                Section::make(__('dberp.sections.admin_user_access'))
                    ->schema([
                        TextInput::make('password')
                            ->label(__('dberp.fields.admin_password'))
                            ->password()
                            ->revealable()
                            ->required(fn (string $operation): bool => $operation === 'create')
                            ->same('password_confirmation')
                            ->dehydrated(fn (?string $state): bool => filled($state)),
                        TextInput::make('password_confirmation')
                            ->label(__('dberp.fields.password_confirmation'))
                            ->password()
                            ->revealable()
                            ->required(fn (string $operation): bool => $operation === 'create')
                            ->requiredWith('password')
                            ->same('password')
                            ->dehydrated(false),
                        Select::make('role_ids')
                            ->label(__('dberp.fields.bound_roles'))
                            ->options(fn (): array => static::roleOptions())
                            ->multiple()
                            ->searchable()
                            ->preload()
                            ->required()
                            ->disabled(fn (?User $record): bool => $record instanceof User && $record->isBootstrapInstallAdmin())
                            ->helperText(fn (?User $record): ?string => $record instanceof User && $record->isBootstrapInstallAdmin()
                                ? (string) __('dberp.hints.bootstrap_admin_roles_readonly')
                                : null)
                            ->columnSpanFull(),
                    ])
                    ->columns(2),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('created_at', 'desc')
            ->columns([
                TextColumn::make('name')
                    ->label(__('dberp.fields.admin_name'))
                    ->searchable(),
                TextColumn::make('nickname')
                    ->label(__('dberp.fields.nickname'))
                    ->searchable()
                    ->placeholder('-'),
                TextColumn::make('login_account')
                    ->label(__('dberp.fields.login_account'))
                    ->searchable(),
                TextColumn::make('email')
                    ->label(__('dberp.fields.email'))
                    ->searchable()
                    ->placeholder('-'),
                TextColumn::make('admin_roles_display')
                    ->label(__('dberp.fields.bound_roles'))
                    ->state(fn (User $record): string => $record->adminRoles->pluck('display_name')->join('、'))
                    ->placeholder('未绑定')
                    ->wrap(),
                TextColumn::make('status')
                    ->label(__('dberp.fields.status'))
                    ->badge()
                    ->state(fn (User $record): string => $record->status?->label() ?? AdminUserStatus::Enabled->label())
                    ->color(fn (User $record): string => $record->isAdminEnabled() ? 'success' : 'gray'),
                TextColumn::make('last_login_at')
                    ->label(__('dberp.fields.last_login_at'))
                    ->dateTime()
                    ->placeholder('-')
                    ->sortable(),
                TextColumn::make('created_at')
                    ->label(__('dberp.fields.created_at'))
                    ->dateTime()
                    ->sortable(),
            ])
            ->filters([
                SelectFilter::make('status')
                    ->label(__('dberp.fields.status'))
                    ->options(AdminUserStatus::options()),
                SelectFilter::make('role_id')
                    ->label(__('dberp.fields.bound_roles'))
                    ->options(fn (): array => static::roleOptions())
                    ->query(function (Builder $query, array $data): Builder {
                        $roleId = $data['value'] ?? null;

                        if (! $roleId) {
                            return $query;
                        }

                        return $query->whereHas('adminRoles', fn (Builder $builder): Builder => $builder->whereKey((int) $roleId));
                    }),
                Filter::make('keyword')
                    ->schema([
                        TextInput::make('value')->label(__('dberp.fields.keyword')),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        $keyword = trim((string) ($data['value'] ?? ''));

                        if ($keyword === '') {
                            return $query;
                        }

                        return $query->where(function (Builder $builder) use ($keyword): void {
                            $builder
                                ->where('name', 'like', "%{$keyword}%")
                                ->orWhere('nickname', 'like', "%{$keyword}%")
                                ->orWhere('login_account', 'like', "%{$keyword}%")
                                ->orWhere('email', 'like', "%{$keyword}%");
                        });
                    }),
            ])
            ->recordActions([
                EditAction::make()
                    ->label(__('dberp.actions.edit')),
                DeleteAction::make()
                    ->label(__('dberp.actions.delete'))
                    ->visible(fn (User $record): bool => static::canDelete($record))
                    ->using(static::deleteAdminUserUsing()),
                Action::make('reset_password')
                    ->label(__('dberp.actions.reset_password'))
                    ->color('warning')
                    ->visible(fn (User $record): bool => static::canResetPassword($record))
                    ->form([
                        TextInput::make('password')
                            ->label(__('dberp.fields.admin_password'))
                            ->password()
                            ->revealable()
                            ->required()
                            ->same('password_confirmation'),
                        TextInput::make('password_confirmation')
                            ->label(__('dberp.fields.password_confirmation'))
                            ->password()
                            ->revealable()
                            ->required()
                            ->same('password'),
                    ])
                    ->action(function (User $record, array $data): void {
                        try {
                            app(DberpAdminAccessService::class)->resetUserPassword(
                                $record,
                                (string) $data['password'],
                                Auth::user(),
                                '管理员管理页重置密码',
                            );

                            Notification::make()
                                ->title((string) __('dberp.notifications.saved'))
                                ->body((string) __('dberp.actions.reset_password'))
                                ->success()
                                ->send();
                        } catch (AuthorizationException|DomainException $exception) {
                            Notification::make()
                                ->title($exception->getMessage())
                                ->danger()
                                ->send();
                        }
                    }),
                Action::make('toggle_status')
                    ->label(fn (User $record): string => $record->isAdminEnabled() ? (string) __('dberp.actions.disable') : (string) __('dberp.actions.enable'))
                    ->color(fn (User $record): string => $record->isAdminEnabled() ? 'danger' : 'success')
                    ->requiresConfirmation()
                    ->modalDescription(fn (User $record): string => $record->isAdminEnabled() ? '停用后，该账号将不能继续进入后台。' : '启用后，该账号可继续进入后台。')
                    ->visible(fn (User $record): bool => static::canToggleStatus($record))
                    ->action(function (User $record): void {
                        try {
                            $status = $record->isAdminEnabled()
                                ? AdminUserStatus::Disabled
                                : AdminUserStatus::Enabled;

                            app(DberpAdminAccessService::class)->updateUserStatus(
                                $record,
                                $status,
                                Auth::user(),
                                '管理员管理页调整账号状态',
                            );

                            Notification::make()
                                ->title((string) __('dberp.notifications.completed'))
                                ->body($status->label())
                                ->success()
                                ->send();
                        } catch (AuthorizationException|DomainException $exception) {
                            Notification::make()
                                ->title($exception->getMessage())
                                ->danger()
                                ->send();
                        }
                    }),
            ]);
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with([
                'adminRoles' => fn ($query) => $query->orderBy('sort_order')->orderBy('id'),
            ])
            ->where(function (Builder $query): void {
                $query
                    ->whereHas('adminRoles')
                    ->orWhereHas('dberpPermissionGrants');
            });
    }

    public static function getPages(): array
    {
        return [
            'index' => ListDberpAdminUsers::route('/'),
            'create' => CreateDberpAdminUser::route('/create'),
            'edit' => EditDberpAdminUser::route('/{record}/edit'),
        ];
    }

    public static function canViewAny(): bool
    {
        return static::allowsAnyPermission([
            DberpPermissionService::VIEW_ADMIN_USER,
            DberpPermissionService::CREATE_ADMIN_USER,
            DberpPermissionService::EDIT_ADMIN_USER,
            DberpPermissionService::DISABLE_ADMIN_USER,
            DberpPermissionService::RESET_ADMIN_USER_PASSWORD,
            DberpPermissionService::DELETE_ADMIN_USER,
        ]);
    }

    public static function canCreate(): bool
    {
        return static::allowsPermission(DberpPermissionService::CREATE_ADMIN_USER);
    }

    public static function canEdit(Model $record): bool
    {
        $currentUser = Auth::user();

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

        if (! static::allowsPermission(DberpPermissionService::EDIT_ADMIN_USER)) {
            return false;
        }

        if ($record instanceof User && $record->isSuperAdmin() && ! $currentUser->isSuperAdmin()) {
            return false;
        }

        return true;
    }

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

        if (! static::allowsPermission(DberpPermissionService::DELETE_ADMIN_USER)) {
            return false;
        }

        if ($record->isBootstrapInstallAdmin()) {
            return false;
        }

        $currentUser = Auth::user();

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

        if ($currentUser->is($record)) {
            return false;
        }

        if ($record->isSuperAdmin() && ! $currentUser->isSuperAdmin()) {
            return false;
        }

        return true;
    }

    /**
     * @return \Closure(User): bool
     */
    public static function deleteAdminUserUsing(): \Closure
    {
        return function (User $record): bool {
            try {
                app(DberpAdminAccessService::class)->deleteUser(
                    $record,
                    Auth::user(),
                    (string) __('dberp.messages.audit_remark_admin_user_deleted'),
                );

                return true;
            } catch (AuthorizationException|DomainException $exception) {
                Notification::make()
                    ->title($exception->getMessage())
                    ->danger()
                    ->send();

                return false;
            }
        };
    }

    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.admin_user.label');
    }

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

    /**
     * @return array<int, string>
     */
    private static function roleOptions(): array
    {
        $query = DberpAdminRole::query()
            ->where('status', AdminRoleStatus::Enabled->value)
            ->orderBy('sort_order')
            ->orderBy('id');

        $currentUser = Auth::user();

        if ($currentUser instanceof User && ! $currentUser->isSuperAdmin()) {
            $query->where('is_super_admin', false);
        }

        return $query->pluck('display_name', 'id')->all();
    }

    private static function canResetPassword(User $record): bool
    {
        $currentUser = Auth::user();

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

        if (! static::allowsPermission(DberpPermissionService::RESET_ADMIN_USER_PASSWORD)) {
            return false;
        }

        if ($record->isSuperAdmin() && ! $currentUser->isSuperAdmin()) {
            return false;
        }

        return true;
    }

    private static function canToggleStatus(User $record): bool
    {
        $currentUser = Auth::user();

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

        if (! static::allowsPermission(DberpPermissionService::DISABLE_ADMIN_USER)) {
            return false;
        }

        if ($currentUser->is($record)) {
            return false;
        }

        if ($record->isSuperAdmin() && ! $currentUser->isSuperAdmin()) {
            return false;
        }

        return true;
    }
}
