<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface;
use Drupal\flowdrop_pipeline\Service\JobGenerationService;
use Drupal\flowdrop_runtime\Service\Orchestrator\AsynchronousOrchestrator;
use Drupal\flowdrop_runtime\Service\Orchestrator\OrchestratorPluginManager;
use Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator;
use Drupal\flowdrop_workflow\FlowDropWorkflowInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form for executing workflows with pipeline generation or selection options.
 *
 * Provides a workflow-centric interface that allows users to:
 * - Select a workflow to execute
 * - Choose to generate a new pipeline or select an existing one
 * - Configure execution options and run the pipeline.
 */
class WorkflowExecutionForm extends FormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The orchestrator plugin manager.
   *
   * @var \Drupal\flowdrop_runtime\Service\Orchestrator\OrchestratorPluginManager
   */
  protected OrchestratorPluginManager $orchestratorManager;

  /**
   * The logger service.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected LoggerInterface $logger;

  /**
   * The job generation service.
   *
   * @var \Drupal\flowdrop_pipeline\Service\JobGenerationService
   */
  protected JobGenerationService $jobGenerationService;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected DateFormatterInterface $dateFormatter;

  /**
   * The asynchronous orchestrator.
   *
   * @var \Drupal\flowdrop_runtime\Service\Orchestrator\AsynchronousOrchestrator
   */
  protected AsynchronousOrchestrator $asynchronousOrchestrator;

  /**
   * The synchronous pipeline orchestrator.
   *
   * @var \Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator
   */
  protected SynchronousPipelineOrchestrator $synchronousPipelineOrchestrator;

  /**
   * The messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected MessengerInterface $messengerService;

  /**
   * Constructs a new WorkflowExecutionForm.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\flowdrop_runtime\Service\Orchestrator\OrchestratorPluginManager $orchestrator_manager
   *   The orchestrator plugin manager.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   * @param \Drupal\flowdrop_pipeline\Service\JobGenerationService $job_generation_service
   *   The job generation service.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   * @param \Drupal\flowdrop_runtime\Service\Orchestrator\AsynchronousOrchestrator $asynchronous_orchestrator
   *   The asynchronous orchestrator.
   * @param \Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator $synchronous_pipeline_orchestrator
   *   The synchronous pipeline orchestrator.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    OrchestratorPluginManager $orchestrator_manager,
    LoggerInterface $logger,
    JobGenerationService $job_generation_service,
    DateFormatterInterface $date_formatter,
    AsynchronousOrchestrator $asynchronous_orchestrator,
    SynchronousPipelineOrchestrator $synchronous_pipeline_orchestrator,
    MessengerInterface $messenger,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->orchestratorManager = $orchestrator_manager;
    $this->logger = $logger;
    $this->jobGenerationService = $job_generation_service;
    $this->dateFormatter = $date_formatter;
    $this->asynchronousOrchestrator = $asynchronous_orchestrator;
    $this->synchronousPipelineOrchestrator = $synchronous_pipeline_orchestrator;
    $this->messengerService = $messenger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get("entity_type.manager"),
      $container->get("flowdrop_runtime.orchestrator_manager"),
      $container->get("logger.factory")->get("flowdrop_runtime"),
      $container->get("flowdrop_pipeline.job_generation"),
      $container->get("date.formatter"),
      $container->get("flowdrop_runtime.asynchronous_orchestrator"),
      $container->get("flowdrop_runtime.synchronous_pipeline_orchestrator"),
      $container->get("messenger")
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return "flowdrop_runtime_workflow_execution_form";
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    // Add form description.
    $form["description"] = [
      "#type" => "markup",
      "#markup" => "<p>" . $this->t("Execute a workflow by selecting it and choosing to create a new pipeline or use an existing one.") . "</p>",
    ];

    // Step 1: Workflow Selection.
    $this->buildWorkflowSelection($form, $form_state);

    // Dynamic container for pipeline options.
    $form["pipeline_options_wrapper"] = [
      "#type" => "container",
      "#prefix" => '<div id="pipeline-options-wrapper">',
      "#suffix" => '</div>',
    ];

    // Get selected workflow.
    $selected_workflow_id = $form_state->getValue("workflow_id");
    if ($selected_workflow_id) {
      $this->buildPipelineOptions($form, $form_state, $selected_workflow_id);
    }

    return $form;
  }

  /**
   * Builds the workflow selection section.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function buildWorkflowSelection(array &$form, FormStateInterface $form_state): void {
    $form["workflow_selection"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Step 1: Select Workflow"),
      "#description" => $this->t("Choose a workflow to execute."),
    ];

    // Build workflow options.
    $workflow_options = $this->buildWorkflowOptions();

    if (empty($workflow_options)) {
      $form["workflow_selection"]["no_workflows"] = [
        "#type" => "markup",
        "#markup" => "<p><em>" . $this->t("No workflows are available. Please create a workflow first.") . "</em></p>",
      ];

      $form["workflow_selection"]["create_link"] = [
        "#type" => "link",
        "#title" => $this->t("Create a new workflow"),
        "#url" => Url::fromRoute("flowdrop.workflow.add"),
        "#attributes" => ["class" => ["button", "button--primary"]],
      ];

      return;
    }

    $form["workflow_selection"]["workflow_id"] = [
      "#type" => "select",
      "#title" => $this->t("Workflow"),
      "#description" => $this->t("Select the workflow you want to execute."),
      "#options" => $workflow_options,
      "#empty_option" => $this->t("- Select a workflow -"),
      "#required" => TRUE,
      "#ajax" => [
        "callback" => "::workflowSelectedCallback",
        "wrapper" => "pipeline-options-wrapper",
        "event" => "change",
      ],
    ];
  }

  /**
   * Builds the pipeline options section.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param string $workflow_id
   *   The selected workflow ID.
   */
  protected function buildPipelineOptions(array &$form, FormStateInterface $form_state, string $workflow_id): void {
    // Load workflow and display info.
    $workflow = $this->entityTypeManager
      ->getStorage("flowdrop_workflow")
      ->load($workflow_id);

    if (!$workflow instanceof FlowDropWorkflowInterface) {
      $form["pipeline_options_wrapper"]["error"] = [
        "#type" => "markup",
        "#markup" => "<p class='messages messages--error'>" . $this->t("Selected workflow could not be loaded.") . "</p>",
      ];
      return;
    }

    // Display workflow information.
    $this->buildWorkflowInfo($form, $workflow);

    // Step 2: Pipeline Selection or Generation.
    $form["pipeline_options_wrapper"]["pipeline_action"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Step 2: Pipeline Options"),
      "#description" => $this->t("Choose to create a new pipeline or use an existing one."),
    ];

    // Get existing pipelines for this workflow.
    $existing_pipelines = $this->getExistingPipelinesForWorkflow($workflow_id);

    $pipeline_action_options = [
      "new" => $this->t("Generate a new pipeline"),
    ];

    if (!empty($existing_pipelines)) {
      $pipeline_action_options["existing"] = $this->t("Use an existing pipeline");
    }

    $default_action = $form_state->getValue("pipeline_action", "new");

    $form["pipeline_options_wrapper"]["pipeline_action"]["action"] = [
      "#type" => "radios",
      "#title" => $this->t("Pipeline Action"),
      "#options" => $pipeline_action_options,
      "#default_value" => $default_action,
      "#required" => TRUE,
      "#ajax" => [
        "callback" => "::pipelineActionCallback",
        "wrapper" => "pipeline-details-wrapper",
        "event" => "change",
      ],
    ];

    // Pipeline details container.
    $form["pipeline_options_wrapper"]["pipeline_details"] = [
      "#type" => "container",
      "#prefix" => '<div id="pipeline-details-wrapper">',
      "#suffix" => '</div>',
    ];

    $selected_action = $form_state->getValue("action", $default_action);

    if ($selected_action === "existing" && !empty($existing_pipelines)) {
      // Show existing pipeline selection.
      $this->buildExistingPipelineSelection($form, $form_state, $existing_pipelines);
    }
    else {
      // Show new pipeline options.
      $this->buildNewPipelineOptions($form, $form_state, $workflow);
    }

    // Step 3: Execution Options.
    $this->buildExecutionOptions($form, $form_state);
  }

  /**
   * Builds the workflow information display.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\flowdrop_workflow\FlowDropWorkflowInterface $workflow
   *   The workflow entity.
   */
  protected function buildWorkflowInfo(array &$form, FlowDropWorkflowInterface $workflow): void {
    $nodes = $workflow->getNodes();
    $edges = $workflow->getEdges();

    $form["pipeline_options_wrapper"]["workflow_info"] = [
      "#type" => "details",
      "#title" => $this->t("Workflow Information: @label", ["@label" => $workflow->label()]),
      "#open" => TRUE,
    ];

    $form["pipeline_options_wrapper"]["workflow_info"]["info_table"] = [
      "#type" => "table",
      "#header" => [$this->t("Property"), $this->t("Value")],
      "#rows" => [
        [$this->t("ID"), $workflow->id()],
        [$this->t("Label"), $workflow->label()],
        [$this->t("Description"), $workflow->getDescription() ?: $this->t("No description")],
        [$this->t("Nodes"), count($nodes)],
        [$this->t("Edges"), count($edges)],
        [
          $this->t("Created"),
          $workflow->getCreated() ?
          $this->dateFormatter->format($workflow->getCreated(), "short") :
          $this->t("Unknown"),
        ],
        [
          $this->t("Last Modified"),
          $workflow->getChanged() ?
          $this->dateFormatter->format($workflow->getChanged(), "short") :
          $this->t("Unknown"),
        ],
      ],
    ];

    // Show edit workflow link.
    $workflow_id = $workflow->id();
    if (is_string($workflow_id)) {
      $form["pipeline_options_wrapper"]["workflow_info"]["edit_link"] = [
        "#type" => "link",
        "#title" => $this->t("Edit Workflow"),
        "#url" => Url::fromRoute("flowdrop.workflow.edit", [
          "flowdrop_workflow" => $workflow_id,
        ]),
        "#attributes" => ["class" => ["button", "button--small"]],
      ];
    }
  }

  /**
   * Builds the existing pipeline selection UI.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param array<int|string, \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface> $pipelines
   *   Existing pipelines for the workflow.
   */
  protected function buildExistingPipelineSelection(array &$form, FormStateInterface $form_state, array $pipelines): void {
    $form["pipeline_options_wrapper"]["pipeline_details"]["existing_section"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Select Existing Pipeline"),
    ];

    // Build pipeline options with detailed information.
    $pipeline_options = [];
    $pipeline_details = [];

    foreach ($pipelines as $pipeline) {
      $pipeline_id = $pipeline->id();
      if (!is_string($pipeline_id) && !is_int($pipeline_id)) {
        continue;
      }

      $job_counts = $pipeline->calculateJobCounts();
      $status = $pipeline->getStatus();

      $label = sprintf(
        "%s [%s] - %d jobs (%d pending, %d completed, %d failed)",
        $pipeline->label(),
        ucfirst($status),
        $job_counts["total"],
        $job_counts["pending"],
        $job_counts["completed"],
        $job_counts["failed"]
      );

      $pipeline_options[(string) $pipeline_id] = $label;

      // Store detailed info for display.
      $pipeline_details[(string) $pipeline_id] = [
        "status" => $status,
        "job_counts" => $job_counts,
        "created" => $pipeline->get("created")->value,
        "started" => $pipeline->getStarted(),
        "completed" => $pipeline->getCompleted(),
        "error_message" => $pipeline->getErrorMessage(),
      ];
    }

    $form["pipeline_options_wrapper"]["pipeline_details"]["existing_section"]["existing_pipeline_id"] = [
      "#type" => "radios",
      "#title" => $this->t("Available Pipelines"),
      "#description" => $this->t("Select a pipeline that was previously generated from this workflow."),
      "#options" => $pipeline_options,
      "#required" => FALSE,
    ];

    // Option to regenerate jobs for selected pipeline.
    $form["pipeline_options_wrapper"]["pipeline_details"]["existing_section"]["regenerate_jobs"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Regenerate jobs before execution"),
      "#description" => $this->t("If checked, existing jobs will be cleared and new jobs will be generated from the workflow definition. This is useful if the workflow has been modified."),
      "#default_value" => FALSE,
    ];

    // Option to reset pipeline status.
    $form["pipeline_options_wrapper"]["pipeline_details"]["existing_section"]["reset_pipeline"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Reset pipeline and job status before execution"),
      "#description" => $this->t("If checked, the pipeline and all jobs will be reset to 'pending' status before execution."),
      "#default_value" => TRUE,
    ];

    // Store pipeline details for later use.
    $form_state->set("pipeline_details", $pipeline_details);
  }

  /**
   * Builds the new pipeline options UI.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param \Drupal\flowdrop_workflow\FlowDropWorkflowInterface $workflow
   *   The workflow entity.
   */
  protected function buildNewPipelineOptions(array &$form, FormStateInterface $form_state, FlowDropWorkflowInterface $workflow): void {
    $form["pipeline_options_wrapper"]["pipeline_details"]["new_section"] = [
      "#type" => "fieldset",
      "#title" => $this->t("New Pipeline Configuration"),
    ];

    // Pipeline label.
    $default_label = sprintf("%s - %s", $workflow->label(), $this->dateFormatter->format(time(), "short"));

    $form["pipeline_options_wrapper"]["pipeline_details"]["new_section"]["pipeline_label"] = [
      "#type" => "textfield",
      "#title" => $this->t("Pipeline Label"),
      "#description" => $this->t("A label for the new pipeline. Leave empty to auto-generate."),
      "#default_value" => $default_label,
      "#maxlength" => 255,
    ];

    // Pipeline description.
    $form["pipeline_options_wrapper"]["pipeline_details"]["new_section"]["pipeline_description"] = [
      "#type" => "textarea",
      "#title" => $this->t("Pipeline Description"),
      "#description" => $this->t("An optional description for the new pipeline."),
      "#default_value" => sprintf("Generated from workflow: %s", $workflow->label()),
      "#rows" => 2,
    ];

    // Max concurrent jobs.
    $form["pipeline_options_wrapper"]["pipeline_details"]["new_section"]["max_concurrent_jobs"] = [
      "#type" => "number",
      "#title" => $this->t("Max Concurrent Jobs"),
      "#description" => $this->t("Maximum number of jobs to run simultaneously."),
      "#default_value" => 5,
      "#min" => 1,
      "#max" => 100,
    ];

    // Retry strategy.
    $form["pipeline_options_wrapper"]["pipeline_details"]["new_section"]["retry_strategy"] = [
      "#type" => "select",
      "#title" => $this->t("Retry Strategy"),
      "#description" => $this->t("How to handle job failures."),
      "#options" => [
        "individual" => $this->t("Individual - Retry each failed job independently"),
        "sequential" => $this->t("Sequential - Retry jobs in order"),
        "none" => $this->t("None - Do not retry failed jobs"),
      ],
      "#default_value" => "individual",
    ];
  }

  /**
   * Builds the execution options section.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function buildExecutionOptions(array &$form, FormStateInterface $form_state): void {
    $form["pipeline_options_wrapper"]["execution_options"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Step 3: Execution Options"),
      "#description" => $this->t("Configure how the pipeline should be executed."),
    ];

    // Executor selection.
    $executor_options = $this->buildExecutorOptions();

    $form["pipeline_options_wrapper"]["execution_options"]["executor_id"] = [
      "#type" => "radios",
      "#title" => $this->t("Execution Mode"),
      "#description" => $this->t("Choose how to execute the pipeline."),
      "#options" => $executor_options,
      "#default_value" => "synchronous",
      "#required" => TRUE,
    ];

    // Executor descriptions.
    $form["pipeline_options_wrapper"]["execution_options"]["executor_descriptions"] = [
      "#type" => "details",
      "#title" => $this->t("Execution Mode Details"),
      "#open" => FALSE,
    ];

    $definitions = $this->orchestratorManager->getDefinitions();
    $descriptions = [];
    foreach ($definitions as $id => $definition) {
      $descriptions[] = sprintf(
        "<strong>%s</strong>: %s",
        $definition["label"],
        $definition["description"]
      );
    }

    $form["pipeline_options_wrapper"]["execution_options"]["executor_descriptions"]["content"] = [
      "#type" => "markup",
      "#markup" => "<ul><li>" . implode("</li><li>", $descriptions) . "</li></ul>",
    ];

    // Input data section.
    $form["pipeline_options_wrapper"]["execution_options"]["input_data_section"] = [
      "#type" => "details",
      "#title" => $this->t("Initial Input Data (Optional)"),
      "#description" => $this->t("Provide optional JSON-formatted input data for the pipeline execution."),
      "#open" => FALSE,
    ];

    $form["pipeline_options_wrapper"]["execution_options"]["input_data_section"]["initial_data"] = [
      "#type" => "textarea",
      "#title" => $this->t("Input Data (JSON)"),
      "#description" => $this->t("Enter valid JSON data to pass as initial input to the pipeline. Leave empty for no initial data."),
      "#default_value" => "{}",
      "#rows" => 5,
    ];

    // Execute immediately option.
    $form["pipeline_options_wrapper"]["execution_options"]["execute_immediately"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Execute pipeline immediately after creation"),
      "#description" => $this->t("If checked, the pipeline will be executed automatically. If unchecked, the pipeline will be created but not started."),
      "#default_value" => TRUE,
    ];

    // Submit button.
    $form["pipeline_options_wrapper"]["actions"] = [
      "#type" => "actions",
    ];

    $form["pipeline_options_wrapper"]["actions"]["submit"] = [
      "#type" => "submit",
      "#value" => $this->t("Execute Workflow"),
      "#button_type" => "primary",
    ];

    $form["pipeline_options_wrapper"]["actions"]["create_only"] = [
      "#type" => "submit",
      "#value" => $this->t("Create Pipeline Only"),
      "#submit" => ["::submitCreateOnly"],
    ];
  }

  /**
   * AJAX callback for workflow selection.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return array<string, mixed>
   *   The pipeline options wrapper.
   */
  public function workflowSelectedCallback(array &$form, FormStateInterface $form_state): array {
    return $form["pipeline_options_wrapper"];
  }

  /**
   * AJAX callback for pipeline action selection.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   The AJAX response.
   */
  public function pipelineActionCallback(array &$form, FormStateInterface $form_state): AjaxResponse {
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand(
      "#pipeline-details-wrapper",
      $form["pipeline_options_wrapper"]["pipeline_details"]
    ));
    return $response;
  }

  /**
   * Builds the workflow options for the select element.
   *
   * @return array<string, string>
   *   An array of workflow options keyed by workflow ID.
   */
  protected function buildWorkflowOptions(): array {
    $options = [];

    try {
      $workflows = $this->entityTypeManager
        ->getStorage("flowdrop_workflow")
        ->loadMultiple();

      foreach ($workflows as $workflow) {
        if ($workflow instanceof FlowDropWorkflowInterface) {
          $workflow_id = $workflow->id();
          if (is_string($workflow_id)) {
            $nodes = $workflow->getNodes();
            $label = sprintf(
              "%s (%d nodes)",
              $workflow->label(),
              count($nodes)
            );
            $options[$workflow_id] = $label;
          }
        }
      }
    }
    catch (\Exception $e) {
      $this->logger->error("Failed to load workflows: @message", [
        "@message" => $e->getMessage(),
      ]);
    }

    return $options;
  }

  /**
   * Builds the executor options from the orchestrator plugin manager.
   *
   * @return array<string, string>
   *   An array of executor options keyed by orchestrator ID.
   */
  protected function buildExecutorOptions(): array {
    $options = [];

    $definitions = $this->orchestratorManager->getDefinitions();
    foreach ($definitions as $id => $definition) {
      $options[$id] = $definition["label"];
    }

    return $options;
  }

  /**
   * Gets existing pipelines for a workflow.
   *
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return array<int|string, \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface>
   *   Array of pipeline entities.
   */
  protected function getExistingPipelinesForWorkflow(string $workflow_id): array {
    $pipelines = [];

    try {
      $storage = $this->entityTypeManager->getStorage("flowdrop_pipeline");
      $query = $storage->getQuery()
        ->condition("workflow_id", $workflow_id)
        ->accessCheck(TRUE)
        ->sort("created", "DESC");

      $ids = $query->execute();

      if (!empty($ids)) {
        $loaded_pipelines = $storage->loadMultiple($ids);
        foreach ($loaded_pipelines as $pipeline) {
          if ($pipeline instanceof FlowDropPipelineInterface) {
            $pipeline_id = $pipeline->id();
            if (is_int($pipeline_id) || is_string($pipeline_id)) {
              $pipelines[$pipeline_id] = $pipeline;
            }
          }
        }
      }
    }
    catch (\Exception $e) {
      $this->logger->error("Failed to load pipelines for workflow @workflow_id: @message", [
        "@workflow_id" => $workflow_id,
        "@message" => $e->getMessage(),
      ]);
    }

    return $pipelines;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    // Validate workflow selection.
    $workflow_id = $form_state->getValue("workflow_id");
    if (empty($workflow_id)) {
      $form_state->setErrorByName("workflow_id", $this->t("Please select a workflow."));
      return;
    }

    // Validate workflow exists.
    $workflow = $this->entityTypeManager
      ->getStorage("flowdrop_workflow")
      ->load($workflow_id);

    if (!$workflow instanceof FlowDropWorkflowInterface) {
      $form_state->setErrorByName("workflow_id", $this->t("The selected workflow does not exist."));
      return;
    }

    // Validate workflow has nodes.
    $nodes = $workflow->getNodes();
    if (empty($nodes)) {
      $form_state->setErrorByName("workflow_id", $this->t("The selected workflow has no nodes. Please add nodes to the workflow first."));
      return;
    }

    // Validate pipeline action.
    $pipeline_action = $form_state->getValue("action");
    if ($pipeline_action === "existing") {
      $existing_pipeline_id = $form_state->getValue("existing_pipeline_id");
      if (empty($existing_pipeline_id)) {
        $form_state->setErrorByName("existing_pipeline_id", $this->t("Please select an existing pipeline."));
        return;
      }

      // Validate pipeline exists.
      $pipeline = $this->entityTypeManager
        ->getStorage("flowdrop_pipeline")
        ->load($existing_pipeline_id);

      if (!$pipeline instanceof FlowDropPipelineInterface) {
        $form_state->setErrorByName("existing_pipeline_id", $this->t("The selected pipeline does not exist."));
      }
    }

    // Validate executor selection.
    $executor_id = $form_state->getValue("executor_id");
    if (empty($executor_id)) {
      $form_state->setErrorByName("executor_id", $this->t("Please select an execution mode."));
      return;
    }

    // Validate executor exists.
    if (!$this->orchestratorManager->hasDefinition($executor_id)) {
      $form_state->setErrorByName("executor_id", $this->t("The selected execution mode is not available."));
      return;
    }

    // Validate input data JSON.
    $initial_data = $form_state->getValue("initial_data");
    if (!empty($initial_data) && $initial_data !== "{}") {
      $decoded = json_decode($initial_data, TRUE);
      if (json_last_error() !== JSON_ERROR_NONE) {
        $form_state->setErrorByName("initial_data", $this->t("The input data must be valid JSON. Error: @error", [
          "@error" => json_last_error_msg(),
        ]));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $this->processForm($form_state, TRUE);
  }

  /**
   * Submit handler for creating pipeline without execution.
   *
   * @param array<string, mixed> $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  public function submitCreateOnly(array &$form, FormStateInterface $form_state): void {
    $this->processForm($form_state, FALSE);
  }

  /**
   * Processes the form submission.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param bool $execute
   *   Whether to execute the pipeline after creation.
   */
  protected function processForm(FormStateInterface $form_state, bool $execute): void {
    $workflow_id = $form_state->getValue("workflow_id");
    $pipeline_action = $form_state->getValue("action");
    $executor_id = $form_state->getValue("executor_id");
    $initial_data_json = $form_state->getValue("initial_data");
    $execute_immediately = (bool) $form_state->getValue("execute_immediately");

    // Parse initial data.
    $initial_data = [];
    if (!empty($initial_data_json) && $initial_data_json !== "{}") {
      $decoded = json_decode($initial_data_json, TRUE);
      if (is_array($decoded)) {
        $initial_data = $decoded;
      }
    }

    try {
      // Get or create the pipeline.
      if ($pipeline_action === "existing") {
        $pipeline = $this->handleExistingPipeline($form_state);
      }
      else {
        $pipeline = $this->createNewPipeline($form_state, $workflow_id);
      }

      if (!$pipeline instanceof FlowDropPipelineInterface) {
        $this->messengerService->addError($this->t("Failed to create or load the pipeline."));
        return;
      }

      // Set input data if provided.
      if (!empty($initial_data)) {
        $pipeline->setInputData($initial_data);
        $pipeline->save();
      }

      $this->logger->info("Pipeline @pipeline_id prepared for workflow @workflow_id", [
        "@pipeline_id" => $pipeline->id(),
        "@workflow_id" => $workflow_id,
      ]);

      // Execute if requested.
      if ($execute && $execute_immediately) {
        $this->executePipeline($pipeline, $executor_id);
      }
      else {
        $this->messengerService->addStatus($this->t("Pipeline '@label' created successfully. You can execute it later from the pipeline interaction page.", [
          "@label" => $pipeline->label(),
        ]));

        // Redirect to pipeline interaction form.
        $form_state->setRedirect(
          "flowdrop.execute.interact",
          [],
          ["query" => ["pipeline_id" => $pipeline->id()]]
        );
      }

    }
    catch (\Exception $e) {
      $this->messengerService->addError($this->t("Operation failed: @message", [
        "@message" => $e->getMessage(),
      ]));

      $this->logger->error("Workflow execution failed for workflow @workflow_id: @message", [
        "@workflow_id" => $workflow_id,
        "@message" => $e->getMessage(),
        "@trace" => $e->getTraceAsString(),
      ]);
    }
  }

  /**
   * Handles selecting an existing pipeline.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface|null
   *   The pipeline entity or NULL if not found.
   */
  protected function handleExistingPipeline(FormStateInterface $form_state): ?FlowDropPipelineInterface {
    $existing_pipeline_id = $form_state->getValue("existing_pipeline_id");
    $regenerate_jobs = (bool) $form_state->getValue("regenerate_jobs");
    $reset_pipeline = (bool) $form_state->getValue("reset_pipeline");

    $pipeline = $this->entityTypeManager
      ->getStorage("flowdrop_pipeline")
      ->load($existing_pipeline_id);

    if (!$pipeline instanceof FlowDropPipelineInterface) {
      return NULL;
    }

    // Regenerate jobs if requested.
    if ($regenerate_jobs) {
      $this->jobGenerationService->clearJobs($pipeline);
      $this->jobGenerationService->generateJobs($pipeline);
      $this->messengerService->addStatus($this->t("Jobs regenerated for pipeline '@label'.", [
        "@label" => $pipeline->label(),
      ]));
    }

    // Reset pipeline status if requested.
    if ($reset_pipeline) {
      $this->resetPipelineAndJobs($pipeline);
      $this->messengerService->addStatus($this->t("Pipeline '@label' reset to pending status.", [
        "@label" => $pipeline->label(),
      ]));
    }

    return $pipeline;
  }

  /**
   * Creates a new pipeline from a workflow.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface|null
   *   The created pipeline entity or NULL on failure.
   */
  protected function createNewPipeline(FormStateInterface $form_state, string $workflow_id): ?FlowDropPipelineInterface {
    $pipeline_label = $form_state->getValue("pipeline_label");
    $pipeline_description = $form_state->getValue("pipeline_description");
    $max_concurrent_jobs = (int) $form_state->getValue("max_concurrent_jobs", 5);
    $retry_strategy = $form_state->getValue("retry_strategy", "individual");

    // Create the pipeline.
    $pipeline_storage = $this->entityTypeManager->getStorage("flowdrop_pipeline");
    $pipeline = $pipeline_storage->create([
      "bundle" => "default",
      "label" => $pipeline_label,
      "description" => $pipeline_description,
      "workflow_id" => $workflow_id,
      "status" => "pending",
      "max_concurrent_jobs" => $max_concurrent_jobs,
      "retry_strategy" => $retry_strategy,
    ]);

    $pipeline->save();

    $this->messengerService->addStatus($this->t("Pipeline '@label' created successfully.", [
      "@label" => $pipeline->label(),
    ]));

    // Generate jobs for the pipeline.
    if ($pipeline instanceof FlowDropPipelineInterface) {
      $jobs = $this->jobGenerationService->generateJobs($pipeline);
      $this->messengerService->addStatus($this->t("Generated @count jobs for the pipeline.", [
        "@count" => count($jobs),
      ]));

      return $pipeline;
    }

    return NULL;
  }

  /**
   * Executes a pipeline with the specified executor.
   *
   * @param \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface $pipeline
   *   The pipeline to execute.
   * @param string $executor_id
   *   The executor ID (synchronous or asynchronous).
   */
  protected function executePipeline(FlowDropPipelineInterface $pipeline, string $executor_id): void {
    // Check if pipeline has jobs.
    $jobs = $pipeline->getJobs();
    if (empty($jobs)) {
      throw new \RuntimeException("Pipeline has no jobs. Job generation may have failed.");
    }

    $this->logger->info("Executing pipeline @pipeline_id with executor @executor_id", [
      "@pipeline_id" => $pipeline->id(),
      "@executor_id" => $executor_id,
    ]);

    if ($executor_id === "synchronous") {
      // Execute pipeline synchronously.
      $response = $this->synchronousPipelineOrchestrator->executePipeline($pipeline);

      $this->messengerService->addStatus($this->t("Pipeline '@label' executed successfully.", [
        "@label" => $pipeline->label(),
      ]));

      $this->messengerService->addStatus($this->t("Execution completed in @time seconds. Status: @status", [
        "@time" => round($response->getExecutionTime(), 3),
        "@status" => $response->getStatus(),
      ]));

      // Show additional details.
      $metadata = $response->getMetadata();
      if (isset($metadata["executed_jobs"]) && is_array($metadata["executed_jobs"])) {
        $this->messengerService->addStatus($this->t("Executed @count jobs in @iterations iterations.", [
          "@count" => count($metadata["executed_jobs"]),
          "@iterations" => $metadata["iterations"] ?? 1,
        ]));
      }

      // Handle warnings for partial failures.
      if ($response->getStatus() === "failed") {
        $this->messengerService->addWarning($this->t("Some jobs may have failed during execution. Check the pipeline details for more information."));
      }
    }
    elseif ($executor_id === "asynchronous") {
      // Execute pipeline asynchronously.
      $result = $this->asynchronousOrchestrator->startPipeline($pipeline);

      if ($result) {
        $this->messengerService->addStatus($this->t("Pipeline '@label' has been queued for asynchronous execution.", [
          "@label" => $pipeline->label(),
        ]));

        $this->messengerService->addStatus($this->t("The pipeline will be processed in the background. Check the pipeline status page for updates."));
      }
      else {
        throw new \RuntimeException("Failed to queue pipeline for asynchronous execution.");
      }
    }
    else {
      throw new \RuntimeException(sprintf("Unknown executor type: %s", $executor_id));
    }

    $this->logger->info("Pipeline @pipeline_id execution initiated with executor @executor_id", [
      "@pipeline_id" => $pipeline->id(),
      "@executor_id" => $executor_id,
    ]);
  }

  /**
   * Resets the pipeline and all its jobs to pending status.
   *
   * @param \Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface $pipeline
   *   The pipeline to reset.
   */
  protected function resetPipelineAndJobs(FlowDropPipelineInterface $pipeline): void {
    // Reset the pipeline status.
    $pipeline->setStatus("pending");
    $pipeline->setStarted(0);
    $pipeline->setCompleted(0);
    $pipeline->setErrorMessage("");
    $pipeline->save();

    $this->logger->info("Pipeline @pipeline_id reset to pending status", [
      "@pipeline_id" => $pipeline->id(),
    ]);

    // Reset all jobs to pending.
    $jobs = $pipeline->getJobs();
    $reset_count = 0;

    foreach ($jobs as $job) {
      $job->setStatus("pending");
      $job->setStarted(0);
      $job->setCompleted(0);
      $job->setErrorMessage("");
      $job->setRetryCount(0);
      $job->save();
      $reset_count++;
    }

    $this->logger->info("Reset @count jobs to pending status for pipeline @pipeline_id", [
      "@count" => $reset_count,
      "@pipeline_id" => $pipeline->id(),
    ]);
  }

}
