<?php

declare(strict_types=1);

namespace Drupal\flowdrop_trigger\Form\Trait;

use Drupal\flowdrop_trigger\Enum\EventCategory;

/**
 * Provides options/lookup helper methods for the trigger config form.
 *
 * Extracts methods that build select options for event types, entity types,
 * roles, orchestrators, timezones, and label generation.
 *
 * Requirements for using this trait:
 * - The class must have an $eventTypeManager property
 *   of type EventTypePluginManager
 * - The class must have an $orchestratorManager property
 *   of type OrchestratorPluginManager
 * - The class must have an $entityTypeManager property
 *   of type EntityTypeManagerInterface
 * - The class must implement t() for translation
 *
 * @internal This trait is not part of the public API and may change without notice.
 */
trait TriggerFormOptionsTrait {

  /**
   * Get event type options.
   *
   * @param string|null $categoryFilter
   *   Optional category to filter by (e.g., "user").
   *
   * @return array<string, string>|array<string, array<string, string>>
   *   Options array, grouped by category if no filter, or flat array if
   *   filtered.
   */
  protected function getEventTypeOptions(?string $categoryFilter = NULL): array {
    $options = [];
    $definitions = $this->eventTypeManager->getDefinitions();

    foreach ($definitions as $id => $definition) {
      $category = EventCategory::toString($definition["category"] ?? "other");

      // Filter by category if specified.
      if ($categoryFilter !== NULL && $category !== $categoryFilter) {
        continue;
      }

      $label = (string) ($definition["label"] ?? $id);

      // If filtering by category, return flat array. Otherwise group by
      // category.
      if ($categoryFilter !== NULL) {
        $options[$id] = $label;
      }
      else {
        $options[$category][$id] = $label;
      }
    }

    return $options;
  }

  /**
   * Get entity type options.
   *
   * @return array<string, string>
   *   Options array.
   */
  protected function getEntityTypeOptions(): array {
    $options = [];
    $entityTypes = $this->entityTypeManager->getDefinitions();

    foreach ($entityTypes as $id => $definition) {
      if ($definition->getGroup() === "content") {
        $options[$id] = (string) $definition->getLabel();
      }
    }

    asort($options);
    return $options;
  }

  /**
   * Get role options.
   *
   * @return array<string, string>
   *   Options array.
   */
  protected function getRoleOptions(): array {
    $options = [];

    /** @var \Drupal\user\RoleInterface[] $roles */
    $roles = $this->entityTypeManager->getStorage("user_role")->loadMultiple();

    foreach ($roles as $role) {
      $roleId = $role->id();
      if ($roleId !== NULL) {
        $options[$roleId] = (string) $role->label();
      }
    }

    return $options;
  }

  /**
   * Get orchestrator options dynamically from registered orchestrators.
   *
   * Retrieves all orchestrator plugins from the plugin manager and builds
   * a select options array including a "default" option.
   *
   * @return array<string, string>
   *   Options array with orchestrator IDs as keys and labels as values.
   */
  protected function getOrchestratorOptions(): array {
    // Start with "default" option which uses event type's default orchestrator.
    $options = [
      "default" => (string) $this->t("Default (based on event)"),
    ];

    // Get all registered orchestrators from the plugin manager.
    $definitions = $this->orchestratorManager->getDefinitions();

    foreach ($definitions as $id => $definition) {
      $label = $definition["label"] ?? ucfirst(str_replace("_", " ", $id));
      // Convert TranslatableMarkup to string if needed.
      $options[$id] = $label instanceof \Stringable ? (string) $label : $label;
    }

    return $options;
  }

  /**
   * Get human-readable label for an event type.
   *
   * @param string $eventTypeId
   *   The event type plugin ID.
   *
   * @return string
   *   The event type label.
   */
  protected function getEventTypeLabel(string $eventTypeId): string {
    $definitions = $this->eventTypeManager->getDefinitions();

    if (isset($definitions[$eventTypeId])) {
      $label = $definitions[$eventTypeId]["label"] ?? $eventTypeId;
      return $label instanceof \Stringable ? (string) $label : $eventTypeId;
    }

    return $eventTypeId;
  }

  /**
   * Get human-readable label for an entity type.
   *
   * @param string $entityTypeId
   *   The entity type ID.
   *
   * @return string
   *   The entity type label.
   */
  protected function getEntityTypeLabel(string $entityTypeId): string {
    $entityType = $this->entityTypeManager->getDefinition($entityTypeId, FALSE);

    if ($entityType !== NULL) {
      $label = $entityType->getLabel();
      return $label instanceof \Stringable ? (string) $label : $entityTypeId;
    }

    return $entityTypeId;
  }

  /**
   * Get timezone options for the form select.
   *
   * @return array<string, string>
   *   Array of timezone identifiers keyed by identifier.
   */
  protected function getTimezoneOptions(): array {
    $timezones = \DateTimeZone::listIdentifiers();
    $options = [];

    foreach ($timezones as $timezone) {
      $options[$timezone] = $timezone;
    }

    return $options;
  }

  /**
   * Generate label from workflow name and node ID.
   *
   * Format: "Workflow Name (nodeId)"
   *
   * @param string $workflowId
   *   The workflow entity ID.
   * @param string $nodeId
   *   The node ID in the workflow (e.g., "trigger.2").
   *
   * @return string
   *   The generated label, or empty string if workflow not found.
   */
  protected function generateLabelFromWorkflowAndNode(string $workflowId, string $nodeId): string {
    // Load workflow entity to get its label.
    $workflowStorage = $this->entityTypeManager->getStorage("flowdrop_workflow");
    $workflow = $workflowStorage->load($workflowId);
    if ($workflow === NULL) {
      return "";
    }

    $workflowName = $workflow->label();

    // Format: "Workflow Name (nodeId)".
    return sprintf("%s (%s)", $workflowName, $nodeId);
  }

}
