<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Form\Trait;

use Drupal\flowdrop_pipeline\Entity\FlowDropPipelineInterface;
use Drupal\flowdrop_workflow\FlowDropWorkflowInterface;

/**
 * Provides data access and options builders for the execution form.
 *
 * Extracts methods that load workflows, pipelines, and build select
 * options for the workflow execution form.
 *
 * Requirements for using this trait:
 * - The class must have an $entityTypeManager property
 *   of type EntityTypeManagerInterface
 * - The class must have an $orchestratorManager property
 *   of type OrchestratorPluginManager
 * - The class must have a $logger property of type LoggerInterface
 *
 * @internal This trait is not part of the public API and may change without notice.
 */
trait WorkflowExecutionDataAccessTrait {

  /**
   * 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;
  }

}
