<?php

declare(strict_types=1);

namespace App\Support\OpsUx;

use App\Services\Providers\ProviderOperationStartResult;
use App\Support\OperationRunLinks;
use App\Support\ReasonTranslation\NextStepOption;
use App\Support\ReasonTranslation\ReasonPresenter;
use Filament\Actions\Action;
use Filament\Notifications\Notification as FilamentNotification;

final class ProviderOperationStartResultPresenter
{
    public function __construct(
        private readonly ReasonPresenter $reasonPresenter,
    ) {}

    /**
     * @param  array<int, Action>  $extraActions
     */
    public function notification(
        ProviderOperationStartResult $result,
        string $blockedTitle,
        string $runUrl,
        array $extraActions = [],
        string $scopeBusyTitle = 'Scope busy',
        string $scopeBusyBody = 'Another provider-backed operation is already running for this scope. Open the active operation for progress and next steps.',
    ): FilamentNotification {
        $notification = match ($result->status) {
            'started' => OperationUxPresenter::queuedToast((string) $result->run->type),
            'deduped' => OperationUxPresenter::alreadyRunningToast((string) $result->run->type),
            'scope_busy' => OperationUxPresenter::scopeBusyToast($scopeBusyTitle, $scopeBusyBody),
            'blocked' => FilamentNotification::make()
                ->title($blockedTitle)
                ->body(implode("\n", $this->blockedBodyLines($result)))
                ->warning(),
            default => OperationUxPresenter::queuedToast((string) $result->run->type),
        };

        return $notification->actions($this->actionsFor($result, $runUrl, $extraActions));
    }

    /**
     * @param  array<int, Action>  $extraActions
     * @return array<int, Action>
     */
    private function actionsFor(ProviderOperationStartResult $result, string $runUrl, array $extraActions): array
    {
        $actions = [
            Action::make('view_run')
                ->label(OperationRunLinks::openLabel())
                ->url($runUrl),
        ];

        if ($result->status === 'blocked') {
            $nextStep = $this->firstNextStep($result);

            if ($nextStep instanceof NextStepOption && $nextStep->kind === 'link' && is_string($nextStep->destination) && trim($nextStep->destination) !== '') {
                $actions[] = Action::make('next_step_0')
                    ->label($nextStep->label)
                    ->url($nextStep->destination);
            }
        }

        return [...$actions, ...$extraActions];
    }

    /**
     * @return array<int, string>
     */
    private function blockedBodyLines(ProviderOperationStartResult $result): array
    {
        $reasonEnvelope = $this->reasonPresenter->forOperationRun($result->run, 'notification');

        return $reasonEnvelope?->toBodyLines() ?? ['Blocked by provider configuration.'];
    }

    private function firstNextStep(ProviderOperationStartResult $result): ?NextStepOption
    {
        $nextSteps = is_array($result->run->context['next_steps'] ?? null)
            ? $result->run->context['next_steps']
            : [];

        $storedNextStep = NextStepOption::collect($nextSteps)[0] ?? null;

        if ($storedNextStep instanceof NextStepOption) {
            return $storedNextStep;
        }

        $reasonEnvelope = $this->reasonPresenter->forOperationRun($result->run, 'notification');

        return $reasonEnvelope?->firstNextStep();
    }
}