<?php

namespace App\Filament\Resources\TenantResource\RelationManagers;

use App\Models\Tenant;
use App\Models\TenantMembership;
use App\Models\User;
use App\Services\Auth\TenantMembershipManager;
use App\Support\TenantRole;
use Filament\Actions;
use Filament\Forms;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Gate;

class TenantMembershipsRelationManager extends RelationManager
{
    protected static string $relationship = 'memberships';

    public function table(Table $table): Table
    {
        return $table
            ->modifyQueryUsing(fn (Builder $query) => $query->with('user'))
            ->columns([
                Tables\Columns\TextColumn::make('user.name')
                    ->label('User')
                    ->searchable(),
                Tables\Columns\TextColumn::make('user.email')
                    ->label('Email')
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('role')
                    ->badge()
                    ->sortable(),
                Tables\Columns\TextColumn::make('source')
                    ->badge()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('created_at')->since(),
            ])
            ->headerActions([
                Actions\Action::make('add_member')
                    ->label('Add member')
                    ->icon('heroicon-o-plus')
                    ->visible(function (): bool {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            return false;
                        }

                        return Gate::allows('tenant_membership.manage', $tenant);
                    })
                    ->form([
                        Forms\Components\Select::make('user_id')
                            ->label('User')
                            ->required()
                            ->searchable()
                            ->options(fn () => User::query()->orderBy('name')->pluck('name', 'id')->all()),
                        Forms\Components\Select::make('role')
                            ->label('Role')
                            ->required()
                            ->options([
                                TenantRole::Owner->value => 'Owner',
                                TenantRole::Manager->value => 'Manager',
                                TenantRole::Operator->value => 'Operator',
                                TenantRole::Readonly->value => 'Readonly',
                            ]),
                    ])
                    ->action(function (array $data, TenantMembershipManager $manager): void {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            abort(404);
                        }

                        $actor = auth()->user();
                        if (! $actor instanceof User) {
                            abort(403);
                        }

                        if (! Gate::allows('tenant_membership.manage', $tenant)) {
                            abort(403);
                        }

                        $member = User::query()->find((int) $data['user_id']);
                        if (! $member) {
                            Notification::make()->title('User not found')->danger()->send();

                            return;
                        }

                        try {
                            $manager->addMember(
                                tenant: $tenant,
                                actor: $actor,
                                member: $member,
                                role: TenantRole::from((string) $data['role']),
                                source: 'manual',
                            );
                        } catch (\Throwable $throwable) {
                            Notification::make()
                                ->title('Failed to add member')
                                ->body($throwable->getMessage())
                                ->danger()
                                ->send();

                            return;
                        }

                        Notification::make()->title('Member added')->success()->send();
                        $this->resetTable();
                    }),
            ])
            ->actions([
                Actions\Action::make('change_role')
                    ->label('Change role')
                    ->icon('heroicon-o-pencil')
                    ->visible(function (): bool {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            return false;
                        }

                        return Gate::allows('tenant_membership.manage', $tenant);
                    })
                    ->form([
                        Forms\Components\Select::make('role')
                            ->label('Role')
                            ->required()
                            ->options([
                                TenantRole::Owner->value => 'Owner',
                                TenantRole::Manager->value => 'Manager',
                                TenantRole::Operator->value => 'Operator',
                                TenantRole::Readonly->value => 'Readonly',
                            ]),
                    ])
                    ->action(function (TenantMembership $record, array $data, TenantMembershipManager $manager): void {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            abort(404);
                        }

                        $actor = auth()->user();
                        if (! $actor instanceof User) {
                            abort(403);
                        }

                        if (! Gate::allows('tenant_membership.manage', $tenant)) {
                            abort(403);
                        }

                        try {
                            $manager->changeRole(
                                tenant: $tenant,
                                actor: $actor,
                                membership: $record,
                                newRole: TenantRole::from((string) $data['role']),
                            );
                        } catch (\Throwable $throwable) {
                            Notification::make()
                                ->title('Failed to change role')
                                ->body($throwable->getMessage())
                                ->danger()
                                ->send();

                            return;
                        }

                        Notification::make()->title('Role updated')->success()->send();
                        $this->resetTable();
                    }),
                Actions\Action::make('remove')
                    ->label('Remove')
                    ->color('danger')
                    ->icon('heroicon-o-x-mark')
                    ->requiresConfirmation()
                    ->visible(function (): bool {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            return false;
                        }

                        return Gate::allows('tenant_membership.manage', $tenant);
                    })
                    ->action(function (TenantMembership $record, TenantMembershipManager $manager): void {
                        $tenant = $this->getOwnerRecord();

                        if (! $tenant instanceof Tenant) {
                            abort(404);
                        }

                        $actor = auth()->user();
                        if (! $actor instanceof User) {
                            abort(403);
                        }

                        if (! Gate::allows('tenant_membership.manage', $tenant)) {
                            abort(403);
                        }

                        try {
                            $manager->removeMember($tenant, $actor, $record);
                        } catch (\Throwable $throwable) {
                            Notification::make()
                                ->title('Failed to remove member')
                                ->body($throwable->getMessage())
                                ->danger()
                                ->send();

                            return;
                        }

                        Notification::make()->title('Member removed')->success()->send();
                        $this->resetTable();
                    }),
            ])
            ->bulkActions([]);
    }
}
