<?php

declare(strict_types=1);

namespace App\Filament\Pages;

use App\Enum\UserLevel;
use App\Models\ImpersonationLog;
use App\Models\User;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\DeleteBulkAction;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Pages\Page;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use UnitEnum;

class ImpersonationLogViewer extends Page implements HasForms, HasTable
{
    use InteractsWithActions;
    use InteractsWithForms;
    use InteractsWithTable;

    protected static string|null|\BackedEnum $navigationIcon = 'heroicon-o-eye';

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

    protected static ?int $navigationSort = 10;

    protected string $view = 'filament.pages.impersonation-log-viewer';

    public function mount(): void
    {
        $this->authorizeAccess();
    }

    protected function authorizeAccess(): void
    {
        $user = Auth::user();

        if (! $user || ! $user->isSuperAdmin()) {
            abort(403, 'Access denied. Only Super Admin can view impersonation logs.');
        }
    }

    public function getTitle(): string
    {
        return 'Impersonation Logs';
    }

    protected function getHeaderActions(): array
    {
        return [
            Action::make('export_csv')
                ->label('Export CSV')
                ->icon('heroicon-o-arrow-down-tray')
                ->color('success')
                ->action(fn () => $this->exportCsv()),

            Action::make('refresh')
                ->label('Refresh')
                ->icon('heroicon-o-arrow-path')
                ->color('gray')
                ->action(fn () => $this->resetTable()),
        ];
    }

    protected function getHeaderWidgets(): array
    {
        return [
            \App\Filament\Widgets\ImpersonationStatsOverview::class,
        ];
    }

    public function table(Table $table): Table
    {
        return $table
            ->query(
                ImpersonationLog::query()
                    ->with(['admin', 'targetUser'])
                    ->latest('start_time')
            )
            ->columns([
                TextColumn::make('id')
                    ->label('ID')
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),

                TextColumn::make('admin.name')
                    ->label('Admin')
                    ->description(fn (ImpersonationLog $record): string => $record->admin?->email ?? 'Unknown')
                    ->sortable()
                    ->searchable()
                    ->weight('medium'),

                TextColumn::make('targetUser.name')
                    ->label('Target User')
                    ->description(fn (ImpersonationLog $record): string => $record->targetUser?->email ?? 'Unknown')
                    ->sortable()
                    ->searchable()
                    ->weight('medium'),

                TextColumn::make('start_time')
                    ->label('Started')
                    ->dateTime('M j, Y g:i A')
                    ->sortable()
                    ->description(fn (ImpersonationLog $record): string => $record->start_time->diffForHumans()),

                TextColumn::make('end_time')
                    ->label('Ended')
                    ->dateTime('M j, Y g:i A')
                    ->sortable()
                    ->placeholder('Active session')
                    ->description(fn (ImpersonationLog $record): string => $record->end_time ? $record->end_time->diffForHumans() : 'Still active'
                    ),

                TextColumn::make('duration_in_minutes')
                    ->label('Duration')
                    ->formatStateUsing(function ($record) {
                        return match(true) {
                            !$record->duration_in_minutes => 'Active',
                            $record->duration_in_minutes < 60 => "{$record->duration_in_minutes}m",
                            default => round($record->duration_in_minutes / 60, 1) . 'h',
                        };
                    })
                    ->sortable()
                    ->alignCenter(),

                TextColumn::make('status')
                    ->label('Status')
                    ->formatStateUsing(function ($record) {
                        return match ($record->status) {
                            'active' => 'Active',
                            'completed' => 'Completed',
                            'force_terminated' => 'Terminated',
                            'expired' => 'Expired',
                            default => 'Unknown',
                        };
                    })
                    ->badge()
                    ->color(fn ($record) => match ($record->status) {
                        'active' => 'success',
                        'completed' => 'primary',
                        'force_terminated' => 'danger',
                        'expired' => 'warning',
                        default => 'gray',
                    }),

                TextColumn::make('ip_address')
                    ->label('IP Address')
                    ->searchable()
                    ->toggleable(isToggledHiddenByDefault: true)
                    ->copyable()
                    ->fontFamily('mono'),

                TextColumn::make('pages_visited_count')
                    ->label('Pages')
                    ->formatStateUsing(fn (ImpersonationLog $record): int => is_array($record->pages_visited) ? count($record->pages_visited) : 0
                    )
                    ->alignCenter()
                    ->toggleable(),

                TextColumn::make('actions_taken_count')
                    ->label('Actions')
                    ->formatStateUsing(fn (ImpersonationLog $record): int => is_array($record->actions_taken) ? count($record->actions_taken) : 0
                    )
                    ->alignCenter()
                    ->toggleable(),
            ])
            ->defaultSort('start_time', 'desc')
            ->filters([
                SelectFilter::make('status')
                    ->label('Status')
                    ->options([
                        'active' => 'Active',
                        'completed' => 'Completed',
                        'force_terminated' => 'Force Terminated',
                        'expired' => 'Expired',
                    ]),

                SelectFilter::make('admin_id')
                    ->label('Admin')
                    ->searchable()
                    ->getSearchResultsUsing(function (string $search): array {
                        return User::where('level', UserLevel::SUPERADMIN->value)
                            ->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%")
                            ->limit(50)
                            ->pluck('name', 'id')
                            ->toArray();
                    })
                    ->getOptionLabelUsing(function ($value): string {
                        return User::find($value)?->name ?? 'Unknown';
                    }),

                SelectFilter::make('target_user_id')
                    ->label('Target User')
                    ->searchable()
                    ->getSearchResultsUsing(function (string $search): array {
                        return User::where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%")
                            ->limit(50)
                            ->pluck('name', 'id')
                            ->toArray();
                    })
                    ->getOptionLabelUsing(function ($value): string {
                        return User::find($value)?->name ?? 'Unknown';
                    }),

                Filter::make('date_range')
                    ->schema([
                        DatePicker::make('start_date')
                            ->label('Start Date')
                            ->required(),
                        DatePicker::make('end_date')
                            ->label('End Date')
                            ->required(),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        return $query
                            ->when(
                                $data['start_date'],
                                fn (Builder $query, $date): Builder => $query->whereDate('start_time', '>=', $date)
                            )
                            ->when(
                                $data['end_date'],
                                fn (Builder $query, $date): Builder => $query->whereDate('start_time', '<=', $date)
                            );
                    }),

                Filter::make('ip_address')
                    ->schema([
                        TextInput::make('ip')
                            ->label('IP Address')
                            ->placeholder('192.168.1.1')
                            ->required(),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        return $query->when(
                            $data['ip'],
                            fn (Builder $query, $ip): Builder => $query->where('ip_address', 'like', "%{$ip}%")
                        );
                    }),
            ])
            ->recordActions([
                Action::make('view_details')
                    ->label('View Details')
                    ->icon('heroicon-o-eye')
                    ->color('primary')
                    ->slideOver()
                    ->modalContent(fn (ImpersonationLog $record): View => view(
                        'filament.modals.impersonation-log-details-slideover',
                        ['record' => $record]
                    ))
                    ->modalHeading('Impersonation Session Details')
                    ->action(fn () => null),

                Action::make('terminate')
                    ->label('Terminate')
                    ->icon('heroicon-o-x-circle')
                    ->color('danger')
                    ->requiresConfirmation()
                    ->modalHeading('Terminate Impersonation Session')
                    ->modalDescription('This will immediately terminate the active impersonation session.')
                    ->modalSubmitActionLabel('Terminate Session')
                    ->visible(fn (ImpersonationLog $record): bool => $record->isActive())
                    ->action(function (ImpersonationLog $record) {
                        $record->update([
                            'end_time' => now(),
                            'status' => 'force_terminated',
                        ]);
                    }),
            ])
            ->toolbarActions([
                BulkActionGroup::make([
                    BulkAction::make('terminate_active')
                        ->label('Terminate Active Sessions')
                        ->icon('heroicon-o-x-circle')
                        ->color('danger')
                        ->requiresConfirmation()
                        ->deselectRecordsAfterCompletion()
                        ->action(function (Collection $records) {
                            $records->filter(fn (ImpersonationLog $record) => $record->isActive())
                                ->each(function (ImpersonationLog $record) {
                                    $record->update([
                                        'end_time' => now(),
                                        'status' => 'force_terminated',
                                    ]);
                                });
                        }),

                    DeleteBulkAction::make(),
                ]),
            ])
            ->emptyStateHeading('No impersonation logs found')
            ->emptyStateDescription('No impersonation sessions have been recorded yet.')
            ->emptyStateActions([
                Action::make('refresh')
                    ->label('Refresh')
                    ->icon('heroicon-o-arrow-path')
                    ->action(fn () => $this->resetTable()),
            ]);
    }

    public function exportCsv()
    {
        $logs = ImpersonationLog::query()
            ->with(['admin', 'targetUser'])
            ->latest('start_time')
            ->get();

        $filename = 'impersonation_logs_' . now()->format('Y_m_d_H_i_s') . '.csv';

        // Create a temporary file
        $handle = fopen('php://temp', 'r+');

        // Add BOM for Excel UTF-8 support
        fwrite($handle, "\xEF\xBB\xBF");

        // Write headers
        $headers = [
            'ID', 'Admin Name', 'Admin Email', 'Target Name', 'Target Email',
            'Start Time', 'End Time', 'Duration (minutes)', 'Status', 'IP Address',
            'User Agent', 'Pages Visited', 'Actions Taken',
        ];
        fputcsv($handle, $headers);

        // Write data rows
        foreach ($logs as $log) {
            fputcsv($handle, [
                $log->id,
                $log->admin?->name ?? 'Unknown',
                $log->admin?->email ?? 'Unknown',
                $log->targetUser?->name ?? 'Unknown',
                $log->targetUser?->email ?? 'Unknown',
                $log->start_time->toDateTimeString(),
                $log->end_time?->toDateTimeString() ?? 'Active',
                $log->duration_in_minutes ?? 'Active',
                $log->status,
                $log->ip_address,
                $log->user_agent,
                is_array($log->pages_visited) ? json_encode($log->pages_visited) : '[]',
                is_array($log->actions_taken) ? json_encode($log->actions_taken) : '[]',
            ]);
        }

        // Rewind the file pointer
        rewind($handle);

        // Get the CSV content
        $csvContent = stream_get_contents($handle);

        // Close the file handle
        fclose($handle);

        // Return a download response
        return response()->streamDownload(
            function () use ($csvContent) {
                echo $csvContent;
            },
            $filename,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="' . $filename . '"',
            ]
        );
    }
}
