<?php

namespace App\Workflows\Actions;

use App\Workflows\Contracts\WorkflowRuntime;
use App\Workflows\Services\StepTemplateService;
use App\Workflows\Traits\HasWorkflow;
use Exception;
use Filament\Actions;
use Filament\Actions\Action;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Textarea;
use Filament\Notifications\Notification;
use Filament\Schemas\Components\Section;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;

class WorkflowActions
{
    /**
     * Get workflow-related actions for a Filament page.
     *
     * @param  Model&HasWorkflow  $record  The model instance that has workflow
     * @param  callable|null  $refreshCallback  Callback to refresh the page data
     * @return array<Actions\Action>
     */
    public static function getActions(Model $record, ?callable $refreshCallback = null): array
    {
        return [
            static::getStartWorkflowAction($record, $refreshCallback),
            static::getReviewStepAction($record, $refreshCallback),
            static::getRejectStepAction($record, $refreshCallback),
        ];
    }

    /**
     * Get localized descriptions for workflow actions.
     *
     * @return array<string, string>
     */
    public static function getActionDescriptions(): array
    {
        return [
            'start_workflow' => __('workflow.descriptions.start_workflow'),
            'review_step' => __('workflow.descriptions.review_step'),
            'reject_step' => __('workflow.descriptions.reject_step'),
            'approve_step' => __('workflow.descriptions.approve_step'),
            'cancel_workflow' => __('workflow.descriptions.cancel_workflow'),
        ];
    }

    /**
     * Get the Start Workflow action.
     */
    public static function getStartWorkflowAction(Model $record, ?callable $refreshCallback = null): Action
    {
        return Action::make('startWorkflow')
            ->label(__('workflow.actions.start_workflow'))
            ->icon('heroicon-o-play')
            ->color('primary')
            ->visible(fn () => ! $record->hasWorkflow())
            ->action(function () use ($record, $refreshCallback) {
                try {
                    $workflowEngine = app(WorkflowRuntime::class);
                    $workflowEngine->ensureInstance($record);

                    // Log the workflow start
                    $record->refresh(); // Refresh to get the new workflow instance
                    $record->logWorkflowStarted();

                    Notification::make()
                        ->title(__('workflow.notifications.workflow_started'))
                        ->success()
                        ->send();

                    if ($refreshCallback) {
                        $refreshCallback(['record']);
                    }
                } catch (Exception $e) {
                    Notification::make()
                        ->title(__('workflow.notifications.workflow_start_failed'))
                        ->body($e->getMessage())
                        ->danger()
                        ->send();
                }
            });
    }

    /**
     * Get the Review/Next Step action.
     */
    public static function getReviewStepAction(Model $record, ?callable $refreshCallback = null): Action
    {
        return Action::make('reviewStep')
            ->label(__('workflow.actions.review_step'))
            ->icon('heroicon-o-check-circle')
            ->color('success')
            ->visible(function () use ($record) {
                // Check if workflow instance is in running state
                if (! $record->hasActiveWorkflow()) {
                    return false;
                }

                $currentStep = $record->currentStep();

                if (! $currentStep || ! $currentStep->isPending()) {
                    return false;
                }

                // Check permission using the step's permission name
                $permission = $currentStep->template->getPermissionName();

                return Auth::user()->can($permission);
            })
            ->schema(function () use ($record) {
                $currentStep = $record->currentStep();

                if (! $currentStep) {
                    return [
                        Textarea::make('note')
                            ->label(__('workflow.forms.note'))
                            ->helperText(__('workflow.forms.note_help')),
                    ];
                }

                $components = [
                    Placeholder::make('step_info')
                        ->label(__('workflow.forms.current_step'))
                        ->content($currentStep->getLabel()),
                ];

                // Get form definition from the step template
                $formDefinition = StepTemplateService::getFormDefinition($currentStep->template);

                if (! empty($formDefinition)) {
                    // Build form components from JSON definition
                    $formComponents = StepTemplateService::buildFormComponents($formDefinition);

                    if (! empty($formComponents)) {
                        $components[] = Section::make(__('workflow.forms.step_form'))
                            ->schema($formComponents);
                    }
                }

                $components[] = Textarea::make('note')
                    ->label(__('workflow.forms.note'))
                    ->helperText(__('workflow.forms.note_help'));

                return $components;
            })
            ->action(function (array $data) use ($record, $refreshCallback) {
                $currentStep = $record->currentStep();

                if (! $currentStep) {
                    Notification::make()
                        ->title(__('workflow.notifications.no_current_step'))
                        ->danger()
                        ->send();

                    return;
                }

                try {
                    // Store step info before approval for logging
                    $fromStep = $currentStep;
                    $stepData = $data;
                    $notes = $data['note'] ?? null;

                    $workflowEngine = app(WorkflowRuntime::class);
                    $workflowEngine->approveStep($currentStep, $data, $notes);

                    // Refresh record and get next step for logging
                    $record->refresh();
                    $toStep = $record->currentStep();

                    // Log the step approval
                    $record->logWorkflowStepApproved($fromStep, $toStep, $stepData, $notes);

                    // If workflow is completed, log that too
                    if (! $toStep && $record->hasWorkflow()) {
                        $record->logWorkflowCompleted($notes);
                    }

                    Notification::make()
                        ->title(__('workflow.notifications.step_approved'))
                        ->success()
                        ->send();

                    if ($refreshCallback) {
                        $refreshCallback(['record']);
                    }
                } catch (Exception $e) {
                    Notification::make()
                        ->title(__('workflow.notifications.step_approval_failed'))
                        ->body($e->getMessage())
                        ->danger()
                        ->send();
                }
            });
    }

    /**
     * Get the Reject Step action.
     */
    public static function getRejectStepAction(Model $record, ?callable $refreshCallback = null): Action
    {
        return Action::make('rejectStep')
            ->label(__('workflow.actions.reject_step'))
            ->icon('heroicon-o-x-circle')
            ->color('danger')
            ->visible(function () use ($record) {
                // Check if workflow instance is in running state
                if (! $record->hasActiveWorkflow()) {
                    return false;
                }

                $currentStep = $record->currentStep();

                if (! $currentStep || ! $currentStep->isPending()) {
                    return false;
                }

                // Check permission using the step's permission name
                $permission = $currentStep->template->getPermissionName();

                return Auth::user()->can($permission);
            })
            ->schema([
                Textarea::make('reason')
                    ->label(__('workflow.forms.rejection_reason'))
                    ->required()
                    ->helperText(__('workflow.forms.rejection_reason_help')),
            ])
            ->action(function (array $data) use ($record, $refreshCallback) {
                $currentStep = $record->currentStep();

                if (! $currentStep) {
                    Notification::make()
                        ->title(__('workflow.notifications.no_current_step'))
                        ->danger()
                        ->send();

                    return;
                }

                try {
                    $reason = $data['reason'];

                    $workflowEngine = app(WorkflowRuntime::class);
                    $workflowEngine->rejectStep($currentStep, $reason);

                    // Log the step rejection
                    $record->logWorkflowStepRejected($currentStep, $reason);

                    Notification::make()
                        ->title(__('workflow.notifications.step_rejected'))
                        ->success()
                        ->send();

                    if ($refreshCallback) {
                        $refreshCallback(['record']);
                    }
                } catch (Exception $e) {
                    Notification::make()
                        ->title(__('workflow.notifications.step_rejection_failed'))
                        ->body($e->getMessage())
                        ->danger()
                        ->send();
                }
            })
            ->requiresConfirmation();
    }

    /**
     * Auto-initialize workflow if none exists.
     * This method can be called from mount() methods of pages.
     */
    public static function autoInitializeWorkflow(Model $record): void
    {
        if (! $record->hasWorkflow()) {
            try {
                $workflowEngine = app(WorkflowRuntime::class);
                $workflowEngine->ensureInstance($record);

                // Refresh the record to load the new workflow instance
                $record->refresh();

                // Log the auto-initialization
                $record->logWorkflowStarted(__('workflow.activity.workflow_auto_started'));
            } catch (Exception $e) {
                // Don't fail if workflow initialization fails, just log it
                logger()->warning('Failed to auto-initialize workflow for model', [
                    'error' => $e->getMessage(),
                    'model_type' => get_class($record),
                    'model_id' => $record->id,
                ]);
            }
        }
    }
}
