<?php

declare(strict_types=1);

namespace App\Filament\Jabali\Pages;

use App\Models\CronJob;
use App\Models\Domain;
use App\Services\Agent\AgentClient;
use BackedEnum;
use Exception;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\Placeholder;
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\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\HtmlString;

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

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

    protected static ?int $navigationSort = 9;

    public static function getNavigationLabel(): string
    {
        return __('Cron Jobs');
    }

    protected string $view = 'filament.jabali.pages.cron-jobs';

    public array $wordPressDomains = [];

    protected ?AgentClient $agent = null;

    public function getTitle(): string|Htmlable
    {
        return __('Cron Jobs');
    }

    public function getAgent(): AgentClient
    {
        if ($this->agent === null) {
            $this->agent = new AgentClient;
        }

        return $this->agent;
    }

    public function getUsername(): string
    {
        return Auth::user()->username;
    }

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

    public function loadWordPressDomains(): void
    {
        try {
            // Get WordPress sites from the agent
            $result = $this->getAgent()->wpList($this->getUsername());
            $sites = $result['sites'] ?? [];

            // Build options array: domain_id => domain name (with path if subdirectory install)
            $this->wordPressDomains = [];
            foreach ($sites as $site) {
                $domain = Domain::where('user_id', Auth::id())
                    ->where('domain', $site['domain'])
                    ->first();

                if ($domain) {
                    $label = $site['domain'];
                    if (! empty($site['path'])) {
                        $label .= '/'.$site['path'];
                    }
                    $this->wordPressDomains[$domain->id] = $label;
                }
            }
        } catch (Exception $e) {
            $this->wordPressDomains = [];
        }
    }

    public function table(Table $table): Table
    {
        return $table
            ->query(CronJob::query()->where('user_id', Auth::id())->orderBy('created_at', 'desc'))
            ->columns([
                TextColumn::make('name')
                    ->label(__('Job Name'))
                    ->icon('heroicon-o-clock')
                    ->iconColor('primary')
                    ->description(fn (CronJob $record) => $record->command)
                    ->searchable()
                    ->sortable(),
                TextColumn::make('schedule')
                    ->label(__('Schedule'))
                    ->fontFamily('mono')
                    ->description(fn (CronJob $record) => $record->schedule_human),
                TextColumn::make('type')
                    ->label(__('Type'))
                    ->badge()
                    ->color(fn (string $state) => $state === 'wordpress' ? 'info' : 'gray')
                    ->formatStateUsing(fn (string $state) => $state === 'wordpress' ? __('WordPress') : __('Custom')),
                IconColumn::make('is_active')
                    ->label(__('Status'))
                    ->boolean()
                    ->trueIcon('heroicon-o-check-circle')
                    ->falseIcon('heroicon-o-pause-circle')
                    ->trueColor('success')
                    ->falseColor('gray'),
                TextColumn::make('last_run_at')
                    ->label(__('Last Run'))
                    ->since()
                    ->description(fn (CronJob $record) => $record->last_run_status ? ($record->last_run_status === 'success' ? __('Success') : __('Failed')) : null)
                    ->placeholder(__('Never'))
                    ->sortable(),
            ])
            ->recordActions([
                Action::make('run')
                    ->label(__('Run Now'))
                    ->icon('heroicon-o-play')
                    ->color('info')
                    ->action(fn (CronJob $record) => $this->runCronJob($record->id)),
                Action::make('viewOutput')
                    ->label(__('View Output'))
                    ->icon('heroicon-o-document-text')
                    ->color('gray')
                    ->visible(fn (CronJob $record) => $record->last_run_at !== null)
                    ->modalHeading(__('Last Run Output'))
                    ->modalDescription(fn (CronJob $record) => __('Last run: :time - Status: :status', [
                        'time' => $record->last_run_at?->diffForHumans(),
                        'status' => $record->last_run_status === 'success' ? __('Success') : __('Failed'),
                    ]))
                    ->modalIcon(fn (CronJob $record) => $record->last_run_status === 'success' ? 'heroicon-o-check-circle' : 'heroicon-o-x-circle')
                    ->modalIconColor(fn (CronJob $record) => $record->last_run_status === 'success' ? 'success' : 'danger')
                    ->modalContent(fn (CronJob $record) => view('filament.jabali.components.cron-output', ['output' => $record->last_run_output]))
                    ->modalSubmitAction(false)
                    ->modalCancelActionLabel(__('Close')),
                Action::make('toggle')
                    ->label(fn (CronJob $record) => $record->is_active ? __('Disable') : __('Enable'))
                    ->icon(fn (CronJob $record) => $record->is_active ? 'heroicon-o-pause' : 'heroicon-o-play-circle')
                    ->color('warning')
                    ->action(fn (CronJob $record) => $this->toggleCronJob($record->id)),
                Action::make('edit')
                    ->label(__('Edit'))
                    ->icon('heroicon-o-pencil')
                    ->color('gray')
                    ->visible(fn (CronJob $record) => $record->type === 'custom')
                    ->modalHeading(__('Edit Cron Job'))
                    ->modalDescription(fn (CronJob $record) => $record->name)
                    ->modalIcon('heroicon-o-pencil')
                    ->modalIconColor('gray')
                    ->modalSubmitActionLabel(__('Save Changes'))
                    ->fillForm(fn (CronJob $record) => [
                        'name' => $record->name,
                        'schedule' => $record->schedule,
                        'command' => $record->command,
                    ])
                    ->form([
                        TextInput::make('name')
                            ->label(__('Job Name'))
                            ->required()
                            ->maxLength(255)
                            ->helperText(__('A friendly name to identify this cron job')),
                        Select::make('schedule')
                            ->label(__('Schedule'))
                            ->options(CronJob::scheduleOptions())
                            ->required()
                            ->searchable()
                            ->helperText(__('How often the command should run')),
                        Textarea::make('command')
                            ->label(__('Command'))
                            ->required()
                            ->rows(3)
                            ->helperText(__('The command will run as your user account')),
                    ])
                    ->action(fn (CronJob $record, array $data) => $this->updateCronJob($record, $data)),
                Action::make('delete')
                    ->label(__('Delete'))
                    ->icon('heroicon-o-trash')
                    ->color('danger')
                    ->requiresConfirmation()
                    ->modalHeading(__('Delete Cron Job'))
                    ->modalDescription(fn (CronJob $record) => __('Are you sure you want to delete')." '{$record->name}'?")
                    ->modalIcon('heroicon-o-trash')
                    ->modalIconColor('danger')
                    ->modalSubmitActionLabel(__('Delete Cron Job'))
                    ->action(fn (CronJob $record) => $this->deleteCronJob($record->id)),
            ])
            ->emptyStateHeading(__('No cron jobs'))
            ->emptyStateDescription(__('Get started by creating a new cron job or setting up WordPress cron.'))
            ->emptyStateIcon('heroicon-o-clock')
            ->striped();
    }

    public function createCronJobAction(): Action
    {
        return Action::make('createCronJob')
            ->label(__('Add Cron Job'))
            ->icon('heroicon-o-plus')
            ->modalHeading(__('Create Cron Job'))
            ->modalDescription(__('Schedule a command to run automatically at specified intervals'))
            ->modalIcon('heroicon-o-clock')
            ->modalIconColor('primary')
            ->modalSubmitActionLabel(__('Create Cron Job'))
            ->modalWidth('lg')
            ->form([
                TextInput::make('name')
                    ->label(__('Job Name'))
                    ->required()
                    ->maxLength(255)
                    ->placeholder(__('My scheduled task'))
                    ->helperText(__('A friendly name to identify this cron job')),
                Select::make('schedule')
                    ->label(__('Schedule'))
                    ->options(CronJob::scheduleOptions())
                    ->required()
                    ->searchable()
                    ->helperText(__('How often the command should run')),
                Textarea::make('command')
                    ->label(__('Command'))
                    ->required()
                    ->rows(3)
                    ->placeholder(__('php /home/user/script.php'))
                    ->helperText(__('The command will run as your user account')),
                Placeholder::make('warning')
                    ->content(new HtmlString('
                        <div class="rounded-lg bg-warning-500/10 p-4 text-sm text-warning-600 dark:text-warning-400">
                            <strong>'.__('Warning:').'</strong> '.__('Cron jobs run automatically at scheduled times. Misconfigured jobs can:').'
                            <ul class="list-disc list-inside mt-2 space-y-1">
                                <li>'.__('Consume excessive server resources').'</li>
                                <li>'.__('Send spam emails if configured incorrectly').'</li>
                                <li>'.__('Cause database locks or corruption').'</li>
                                <li>'.__('Fill up disk space with log files').'</li>
                            </ul>
                            <p class="mt-2">'.__('Only create cron jobs if you understand what the command does.').'</p>
                        </div>
                    ')),
            ])
            ->action(function (array $data): void {
                try {
                    // Create in database - Laravel scheduler will handle execution
                    CronJob::create([
                        'user_id' => Auth::id(),
                        'name' => $data['name'],
                        'schedule' => $data['schedule'],
                        'command' => $data['command'],
                        'type' => 'custom',
                        'is_active' => true,
                    ]);

                    Notification::make()
                        ->title(__('Cron job created'))
                        ->body(__('The job will run according to its schedule.'))
                        ->success()
                        ->send();
                } catch (Exception $e) {
                    Notification::make()
                        ->title(__('Error creating cron job'))
                        ->body($e->getMessage())
                        ->danger()
                        ->send();
                }
            });
    }

    public function setupWordPressCronAction(): Action
    {
        return Action::make('setupWordPressCron')
            ->label(__('Setup WordPress Cron'))
            ->icon('heroicon-o-bolt')
            ->color('info')
            ->modalHeading(__('Setup WordPress Cron'))
            ->modalDescription(__('Replace WordPress\'s built-in cron with a real server cron job for better reliability and performance'))
            ->modalIcon('heroicon-o-bolt')
            ->modalIconColor('info')
            ->modalSubmitActionLabel(__('Setup WordPress Cron'))
            ->modalWidth('lg')
            ->form([
                Select::make('domain_id')
                    ->label(__('WordPress Site'))
                    ->options($this->wordPressDomains)
                    ->required()
                    ->searchable()
                    ->placeholder(__('Select a WordPress site'))
                    ->helperText(__('Select the WordPress site to enable server-side cron for')),
                Select::make('schedule')
                    ->label(__('Run Frequency'))
                    ->options([
                        '*/5 * * * *' => __('Every 5 minutes (Recommended)'),
                        '*/10 * * * *' => __('Every 10 minutes'),
                        '*/15 * * * *' => __('Every 15 minutes'),
                        '*/30 * * * *' => __('Every 30 minutes'),
                        '0 * * * *' => __('Every hour'),
                    ])
                    ->default('*/5 * * * *')
                    ->required()
                    ->helperText(__('How often WordPress scheduled tasks should run')),
                Placeholder::make('info')
                    ->content(new HtmlString('
                        <div class="rounded-lg bg-info-500/10 p-4 text-sm text-info-600 dark:text-info-400">
                            <strong>'.__('What this does:').'</strong>
                            <ul class="list-disc list-inside mt-2 space-y-1">
                                <li>'.__('Creates a server cron job to run').' <code>wp-cron.php</code></li>
                                <li>'.__('Adds').' <code>define(\'DISABLE_WP_CRON\', true);</code> '.__('to your').' <code>wp-config.php</code></li>
                                <li>'.__('Improves scheduled task reliability (posts, backups, updates)').'</li>
                                <li>'.__('Reduces page load times by removing cron checks from visitors').'</li>
                            </ul>
                        </div>
                    ')),
            ])
            ->action(function (array $data): void {
                try {
                    $domain = Domain::findOrFail($data['domain_id']);
                    $username = $this->getUsername();

                    // Add DISABLE_WP_CRON to wp-config.php
                    $result = $this->getAgent()->cronWordPressSetup(
                        $username,
                        $domain->domain,
                        $data['schedule'],
                        false // enable - adds DISABLE_WP_CRON to wp-config
                    );

                    if (! $result['success']) {
                        throw new Exception($result['error'] ?? __('Failed to setup WordPress cron'));
                    }

                    // Save to database - Laravel scheduler will handle execution
                    $command = "cd /home/{$username}/domains/{$domain->domain}/public_html && /usr/bin/php wp-cron.php";

                    CronJob::updateOrCreate(
                        [
                            'user_id' => Auth::id(),
                            'type' => 'wordpress',
                            'metadata->domain_id' => $domain->id,
                        ],
                        [
                            'name' => "WordPress Cron - {$domain->domain}",
                            'schedule' => $data['schedule'],
                            'command' => $command,
                            'is_active' => true,
                            'metadata' => ['domain_id' => $domain->id, 'domain' => $domain->domain],
                        ]
                    );

                    Notification::make()
                        ->title(__('WordPress cron enabled'))
                        ->body(__('Server cron is now handling scheduled tasks for :domain', ['domain' => $domain->domain]))
                        ->success()
                        ->send();
                } catch (Exception $e) {
                    Notification::make()
                        ->title(__('Error setting up WordPress cron'))
                        ->body($e->getMessage())
                        ->danger()
                        ->send();
                }
            });
    }

    public function deleteCronJob(int $id): void
    {
        try {
            $cronJob = CronJob::where('user_id', Auth::id())->findOrFail($id);

            // If it's a WordPress cron, remove the wp-config DISABLE_WP_CRON constant
            if ($cronJob->type === 'wordpress' && isset($cronJob->metadata['domain'])) {
                $this->getAgent()->cronWordPressSetup(
                    $this->getUsername(),
                    $cronJob->metadata['domain'],
                    $cronJob->schedule,
                    true // disable - removes DISABLE_WP_CRON from wp-config
                );
            }

            // Delete from database - Laravel scheduler will stop running it
            $cronJob->delete();

            Notification::make()
                ->title(__('Cron job deleted'))
                ->success()
                ->send();
        } catch (Exception $e) {
            Notification::make()
                ->title(__('Error deleting cron job'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    public function updateCronJob(CronJob $cronJob, array $data): void
    {
        try {
            // Update database - Laravel scheduler uses these values
            $cronJob->update([
                'name' => $data['name'],
                'schedule' => $data['schedule'],
                'command' => $data['command'],
            ]);

            Notification::make()
                ->title(__('Cron job updated'))
                ->success()
                ->send();
        } catch (Exception $e) {
            Notification::make()
                ->title(__('Error updating cron job'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    public function toggleCronJob(int $id): void
    {
        try {
            $cronJob = CronJob::where('user_id', Auth::id())->findOrFail($id);
            $newState = ! $cronJob->is_active;

            // Update database - Laravel scheduler checks is_active
            $cronJob->update(['is_active' => $newState]);

            Notification::make()
                ->title($newState ? __('Cron job enabled') : __('Cron job disabled'))
                ->success()
                ->send();
        } catch (Exception $e) {
            Notification::make()
                ->title(__('Error toggling cron job'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    public function runCronJob(int $id): void
    {
        try {
            $cronJob = CronJob::where('user_id', Auth::id())->findOrFail($id);

            $result = $this->getAgent()->cronRun(
                $this->getUsername(),
                $cronJob->command
            );

            // Update last run info
            $cronJob->update([
                'last_run_at' => now(),
                'last_run_status' => $result['success'] ? 'success' : 'failed',
                'last_run_output' => $result['output'] ?? null,
            ]);

            if ($result['success']) {
                Notification::make()
                    ->title(__('Cron job executed'))
                    ->body(__('Command completed successfully'))
                    ->success()
                    ->send();
            } else {
                Notification::make()
                    ->title(__('Cron job failed'))
                    ->body($result['output'] ?? __('Command failed'))
                    ->warning()
                    ->send();
            }
        } catch (Exception $e) {
            Notification::make()
                ->title(__('Error running cron job'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    protected function getHeaderActions(): array
    {
        return [
            $this->createCronJobAction(),
            $this->setupWordPressCronAction(),
        ];
    }
}
