<?php

namespace App\Filament\Pages;

use App\Models\ActivationKey;
use App\Models\Plan;
use BackedEnum;
use Filament\Actions\BulkAction;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Columns\BadgeColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use UnitEnum;

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

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

    protected string $view = 'filament.pages.generate-activation-keys';

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

    protected static ?string $title = 'Activation Keys';

    public $plan_id;

    public $quantity = 1;

    public $notes;

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

    protected function getFormSchema(): array
    {
        return [
            Select::make('plan_id')
                ->label('Select Plan')
                ->options(function () {
                    return Plan::with('planTier')
                        ->get()
                        ->map(function ($plan) {
                            $tierName = $plan->planTier ? $plan->planTier->name : '';
                            $billingCycle = $plan->getBillingCycleDisplay();
                            $name = $plan->name;

                            if ($tierName) {
                                $name .= " ({$tierName})";
                            }
                            if ($billingCycle) {
                                $name .= " - {$billingCycle}";
                            }

                            return $name;
                        })
                        ->toArray();
                })
                ->required()
                ->reactive()
                ->afterStateUpdated(fn ($state, callable $set) => $set('quantity', 1)),

            TextInput::make('quantity')
                ->label('Number of Keys')
                ->numeric()
                ->minValue(1)
                ->maxValue(100)
                ->default(1)
                ->required()
                ->helperText('Generate multiple keys for bulk distribution'),

            Textarea::make('notes')
                ->label('Generation Notes (Optional)')
                ->rows(2)
                ->placeholder('Add notes about this batch of keys...')
                ->helperText('These notes will be stored with the generated keys for tracking purposes'),
        ];
    }

    public function generate(): void
    {
        try {
            $data = $this->form->getState();
            $plan = Plan::with('planTier')->findOrFail($data['plan_id']);

            $generatedKeys = [];
            $batchId = 'BATCH_'.now()->format('YmdHis').'_'.Str::random(8);

            for ($i = 0; $i < $data['quantity']; $i++) {
                $activationKey = ActivationKey::query()->create([
                    'price_id' => $plan->pricing_id,
                    'activation_key' => $this->generateUniqueActivationKey($plan),
                    'is_activated' => false,
                ]);

                $generatedKeys[] = $activationKey->activation_key;
            }

            // Log the generation for audit purposes
            \Log::info('Activation keys generated', [
                'batch_id' => $batchId,
                'plan_id' => $plan->id,
                'plan_name' => $plan->name,
                'quantity' => $data['quantity'],
                'generated_by' => auth()->id(),
                'notes' => $data['notes'] ?? null,
            ]);

            Notification::make()
                ->title("{$data['quantity']} activation key(s) generated successfully")
                ->body("For {$plan->name} - Batch ID: {$batchId}")
                ->success()
                ->send();

            $this->form->fill(); // Reset form
        } catch (\Exception $exception) {
            $this->form->fill();
            Notification::make()
                ->title('Something went wrong')
                ->body("Error: {$exception->getMessage()}")
                ->danger()
                ->send();
        }

    }

    private function generateUniqueActivationKey(Plan $plan): string
    {
        do {
            // Create a more structured key format: PLAN_PREFIX + RANDOM
            $prefix = strtoupper(substr(str_replace([' ', '-'], '', $plan->name), 0, 3));
            $random = strtoupper(Str::random(13));
            $key = $prefix.$random;
        } while (ActivationKey::where('activation_key', $key)->exists());

        return $key;
    }

    // === Table Setup ===
    protected function getTableQuery(): Builder
    {
        return ActivationKey::query()->latest();
    }

    protected function getTableColumns(): array
    {
        return [
            TextColumn::make('activation_key')
                ->label('Activation Key')
                ->copyable()
                ->searchable()
                ->weight('font-semibold'),

            BadgeColumn::make('status')
                ->label('Status')
                ->getStateUsing(function ($record): string {
                    return $record->is_activated ? 'Activated' : 'Unused';
                })
                ->colors([
                    'success' => 'Activated',
                    'warning' => 'Unused',
                ]),

            TextColumn::make('plan.name')
                ->label('Plan')
                ->getStateUsing(function ($record): string {
                    $plan = Plan::where('pricing_id', $record->price_id)->first();

                    return $plan ? $plan->name : 'Unknown Plan';
                })
                ->searchable(),

            TextColumn::make('plan.planTier.name')
                ->label('Tier')
                ->getStateUsing(function ($record): ?string {
                    $plan = Plan::where('pricing_id', $record->price_id)->first();

                    return $plan && $plan->planTier ? $plan->planTier->name : null;
                }),

            TextColumn::make('user.email')
                ->label('Activated By')
                ->default('Not activated')
                ->searchable(),

            TextColumn::make('billing_cycle')
                ->label('Billing Cycle')
                ->getStateUsing(function ($record): string {
                    $plan = Plan::where('pricing_id', $record->price_id)->first();

                    return $plan ? $plan->getBillingCycleDisplay() : 'Unknown';
                }),

            TextColumn::make('created_at')
                ->label('Generated')
                ->dateTime()
                ->sortable(),
        ];
    }

    protected function getTableFilters(): array
    {
        return [
            SelectFilter::make('is_activated')
                ->label('Status')
                ->options([
                    true => 'Activated',
                    false => 'Not Activated',
                ]),

            SelectFilter::make('price_id')
                ->label('Plan')
                ->options(function () {
                    return Plan::with('planTier')
                        ->get()
                        ->mapWithKeys(function ($plan) {
                            $tierName = $plan->planTier ? " ({$plan->planTier->name})" : '';

                            return [$plan->pricing_id => $plan->name.$tierName];
                        })
                        ->toArray();
                }),

            SelectFilter::make('created_at')
                ->label('Generation Date')
                ->options([
                    'today' => 'Today',
                    'this_week' => 'This Week',
                    'this_month' => 'This Month',
                    'last_month' => 'Last Month',
                ])
                ->query(function (Builder $query, array $data): Builder {
                    if ($data['value'] === 'today') {
                        return $query->whereDate('created_at', today());
                    } elseif ($data['value'] === 'this_week') {
                        return $query->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()]);
                    } elseif ($data['value'] === 'this_month') {
                        return $query->whereMonth('created_at', now()->month)
                            ->whereYear('created_at', now()->year);
                    } elseif ($data['value'] === 'last_month') {
                        return $query->whereMonth('created_at', now()->subMonth()->month)
                            ->whereYear('created_at', now()->subMonth()->year);
                    }

                    return $query;
                }),
        ];
    }

    protected function getTableBulkActions(): array
    {
        return [
            BulkAction::make('Download Keys')
                ->action(fn (Collection $records): BinaryFileResponse => $this->downloadKeys($records))
                ->deselectRecordsAfterCompletion()
                ->requiresConfirmation()
                ->modalDescription('Download selected activation keys as a text file.'),

            BulkAction::make('Deactivate Keys')
                ->action(function (Collection $records) {
                    $count = 0;
                    foreach ($records as $record) {
                        if ($record->is_activated) {
                            // Deactivate the subscription if it exists
                            $subscription = $record->user?->subscriptions()
                                ->where('provider', 'activation_key')
                                ->where('provider_subscription_id', $record->id)
                                ->first();

                            if ($subscription) {
                                $subscription->update([
                                    'status' => 'cancelled',
                                    'ends_at' => now(),
                                ]);
                            }

                            $record->update([
                                'is_activated' => false,
                                'user_id' => null,
                            ]);
                            $count++;
                        }
                    }

                    Notification::make()
                        ->title("{$count} key(s) deactivated")
                        ->success()
                        ->send();
                })
                ->deselectRecordsAfterCompletion()
                ->requiresConfirmation()
                ->modalDescription('This will deactivate the selected keys and cancel associated subscriptions.')
                ->color('danger'),

            BulkAction::make('Delete Keys')
                ->action(function (Collection $records) {
                    $count = $records->count();

                    // First, deactivate any associated subscriptions
                    foreach ($records as $record) {
                        $subscription = $record->user?->subscriptions()
                            ->where('provider', 'activation_key')
                            ->where('provider_subscription_id', $record->id)
                            ->first();

                        if ($subscription) {
                            $subscription->delete();
                        }
                    }

                    // Delete the keys
                    $records->each->delete();

                    Notification::make()
                        ->title("{$count} key(s) deleted")
                        ->success()
                        ->send();
                })
                ->deselectRecordsAfterCompletion()
                ->requiresConfirmation()
                ->modalDescription('This will permanently delete the selected keys and associated subscriptions.')
                ->color('danger'),
        ];
    }

    public function downloadKeys(Collection $records): BinaryFileResponse
    {
        $content = "# Activation Keys\n";
        $content .= '# Generated: '.now()->toDateTimeString()."\n";
        $content .= '# Total Keys: '.$records->count()."\n\n";

        foreach ($records as $record) {
            $plan = Plan::where('pricing_id', $record->price_id)->first();
            $content .= "Key: {$record->activation_key}\n";
            $content .= 'Plan: '.($plan->name ?? 'Unknown Plan')."\n";
            $content .= 'Status: '.($record->is_activated ? 'Activated' : 'Unused')."\n";
            $content .= 'Generated: '.$record->created_at->toDateTimeString()."\n";
            if ($record->user) {
                $content .= 'Activated By: '.$record->user->email."\n";
            }
            $content .= "---\n\n";
        }

        $filename = 'activation_keys_'.now()->format('Y-m-d_H-i-s').'.txt';
        $path = public_path("activation/{$filename}");

        // Make sure the 'activation' folder exists
        if (! file_exists(public_path('activation')) && ! mkdir($concurrentDirectory = public_path('activation'), 0755, true) && ! is_dir($concurrentDirectory)) {
            Log::error('Failed to create activation keys file: '.$concurrentDirectory);
        }

        file_put_contents($path, $content);

        return response()->download($path)->deleteFileAfterSend(true);
    }
}
