<?php

declare(strict_types=1);

namespace Drupal\flowdrop_trigger\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\flowdrop_trigger\Service\EventTypePluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Base class for trigger settings category forms.
 *
 * Provides common functionality for category-specific trigger settings forms.
 * Each category (entity, form, user) extends this base class to provide
 * its own configuration form.
 *
 * This architecture allows contrib modules to:
 * - Add their own category settings forms by extending this base class.
 * - Register their forms via routing and local tasks.
 * - Follow consistent patterns for settings management.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
abstract class TriggerSettingsCategoryFormBase extends ConfigFormBase {

  /**
   * The event type plugin manager.
   *
   * @var \Drupal\flowdrop_trigger\Service\EventTypePluginManager
   */
  protected EventTypePluginManager $eventTypeManager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    $instance = parent::create($container);
    $instance->eventTypeManager = $container->get("plugin.manager.flowdrop_event_type");
    return $instance;
  }

  /**
   * Get the category ID this form handles.
   *
   * @return string
   *   The category ID (e.g., "entity", "form", "user").
   */
  abstract protected function getCategoryId(): string;

  /**
   * Get the category label for display purposes.
   *
   * @return string
   *   The human-readable category label.
   */
  abstract protected function getCategoryLabel(): string;

  /**
   * Get event types for this category.
   *
   * @return array<string, array<string, mixed>>
   *   Array of event type definitions keyed by plugin ID.
   */
  protected function getCategoryEventTypes(): array {
    $eventTypesByCategory = $this->eventTypeManager->getEventTypesByCategory();
    return $eventTypesByCategory[$this->getCategoryId()] ?? [];
  }

  /**
   * Build the enabled/disabled toggle field.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return array<string, mixed>
   *   The form element array.
   */
  protected function buildEnabledField(FormStateInterface $form_state): array {
    $config = $this->config($this->getEditableConfigNames()[0]);

    return [
      "#type" => "checkbox",
      "#title" => $this->t("Enable @category event triggers", [
        "@category" => $this->getCategoryLabel(),
      ]),
      "#description" => $this->t("When disabled, no @category events will trigger workflows.", [
        "@category" => strtolower($this->getCategoryLabel()),
      ]),
      "#default_value" => $config->get("enabled") ?? TRUE,
    ];
  }

  /**
   * Build the event types selection field.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return array<string, mixed>
   *   The form element array.
   */
  protected function buildEventTypesField(FormStateInterface $form_state): array {
    $config = $this->config($this->getEditableConfigNames()[0]);
    $eventTypes = $this->getCategoryEventTypes();
    $allowedEventTypes = $config->get("allowed_event_types") ?? [];

    $options = [];
    foreach ($eventTypes as $eventTypeId => $definition) {
      $label = $definition["label"] ?? $eventTypeId;
      $options[$eventTypeId] = $label instanceof \Stringable ? (string) $label : $eventTypeId;
    }

    $element = [
      "#type" => "details",
      "#title" => $this->t("Event Types"),
      "#open" => !empty($allowedEventTypes),
      "#description" => $this->t("Select which @category event types should trigger workflows. If none selected, all @category event types are allowed.", [
        "@category" => strtolower($this->getCategoryLabel()),
      ]),
      "#tree" => TRUE,
    ];

    $element["allowed_event_types"] = [
      "#type" => "checkboxes",
      "#title" => $this->t("Allowed Event Types"),
      "#options" => $options,
      "#default_value" => array_combine($allowedEventTypes, $allowedEventTypes),
    ];

    // Add descriptions for each event type.
    foreach ($eventTypes as $eventTypeId => $definition) {
      $description = $definition["description"] ?? "";
      if (!empty($description)) {
        $descriptionString = $description instanceof \Stringable ? (string) $description : $description;
        $element["allowed_event_types"][$eventTypeId]["#description"] = $descriptionString;
      }
    }

    return $element;
  }

  /**
   * Filter checkbox values to get only checked items.
   *
   * @param array<string, mixed> $values
   *   The checkbox values from form state.
   *
   * @return array<string>
   *   Array of checked item keys, reindexed.
   */
  protected function filterCheckboxValues(array $values): array {
    $filtered = array_filter(
      $values,
      fn($value) => $value !== 0 && $value !== FALSE && $value !== NULL && $value !== ""
    );
    return array_keys($filtered);
  }

  /**
   * Filter textarea values to get clean array of lines.
   *
   * @param string $value
   *   The textarea value (newline-separated).
   *
   * @return array<string>
   *   Array of non-empty trimmed lines.
   */
  protected function filterTextareaValues(string $value): array {
    $lines = explode("\n", $value);
    $filtered = array_filter(
      array_map("trim", $lines),
      fn($line) => $line !== ""
    );
    return array_values($filtered);
  }

  /**
   * Convert array to textarea value.
   *
   * @param array<string> $values
   *   Array of values.
   *
   * @return string
   *   Newline-separated string.
   */
  protected function arrayToTextarea(array $values): string {
    return implode("\n", $values);
  }

}
