<?php

declare(strict_types=1);

namespace Drupal\flowdrop_trigger\Form;

use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Entity events settings form for FlowDrop Trigger module.
 *
 * Allows configuration of entity-related trigger settings including:
 * - Which entity event types to allow (insert, update, delete, presave)
 * - Which entity types should trigger workflows
 * - Which bundles should trigger workflows
 * - Additional entity-specific options.
 *
 * @see \Drupal\flowdrop_trigger\Form\TriggerSettingsCategoryFormBase
 */
final class TriggerSettingsEntityForm extends TriggerSettingsCategoryFormBase {

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

  /**
   * The entity type bundle info service.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected EntityTypeBundleInfoInterface $bundleInfo;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    $instance = parent::create($container);
    $instance->entityTypeManager = $container->get("entity_type.manager");
    $instance->bundleInfo = $container->get("entity_type.bundle.info");
    return $instance;
  }

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

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames(): array {
    return ["flowdrop_trigger.settings.entity"];
  }

  /**
   * {@inheritdoc}
   */
  protected function getCategoryId(): string {
    return "entity";
  }

  /**
   * {@inheritdoc}
   */
  protected function getCategoryLabel(): string {
    return "Entity";
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $config = $this->config("flowdrop_trigger.settings.entity");

    $form["description"] = [
      "#type" => "markup",
      "#markup" => "<p>" . $this->t("Configure which entity events should trigger workflows. These settings apply to entity lifecycle events (insert, update, delete, presave).") . "</p>",
    ];

    // =========================================================================
    // Master Toggle.
    // =========================================================================
    $form["enabled"] = $this->buildEnabledField($form_state);

    // =========================================================================
    // Event Types Section.
    // =========================================================================
    $form["event_types_wrapper"] = $this->buildEventTypesField($form_state);

    // =========================================================================
    // Entity Types Section.
    // =========================================================================
    $allowedEntityTypes = $config->get("allowed_entity_types") ?? [];

    $form["entity_types_wrapper"] = [
      "#type" => "details",
      "#title" => $this->t("Allowed Entity Types"),
      "#open" => !empty($allowedEntityTypes),
      "#description" => $this->t("Select which entity types should trigger workflows. If none selected, all entity types are allowed."),
      "#tree" => TRUE,
    ];

    $entityTypeOptions = $this->getContentEntityTypeOptions();

    $form["entity_types_wrapper"]["allowed_entity_types"] = [
      "#type" => "checkboxes",
      "#title" => $this->t("Entity Types"),
      "#options" => $entityTypeOptions,
      "#default_value" => array_combine($allowedEntityTypes, $allowedEntityTypes),
    ];

    // =========================================================================
    // Bundles Section.
    // =========================================================================
    $allowedBundles = $config->get("allowed_bundles") ?? [];

    $form["bundles_wrapper"] = [
      "#type" => "details",
      "#title" => $this->t("Allowed Bundles"),
      "#open" => !empty($allowedBundles),
      "#description" => $this->t("Select which bundles should trigger workflows. If none selected, all bundles are allowed. Format: entity_type:bundle."),
      "#tree" => TRUE,
    ];

    $bundleOptions = $this->getBundleOptions();

    $form["bundles_wrapper"]["allowed_bundles"] = [
      "#type" => "checkboxes",
      "#title" => $this->t("Bundles"),
      "#options" => $bundleOptions,
      "#default_value" => array_combine($allowedBundles, $allowedBundles),
    ];

    // =========================================================================
    // Additional Options.
    // =========================================================================
    $form["options"] = [
      "#type" => "details",
      "#title" => $this->t("Additional Options"),
      "#open" => FALSE,
      "#tree" => TRUE,
    ];

    $form["options"]["log_entity_changes"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Log detailed entity changes"),
      "#description" => $this->t("When enabled, detailed information about entity changes is logged. Useful for debugging but may increase log volume."),
      "#default_value" => $config->get("log_entity_changes") ?? FALSE,
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $config = $this->config("flowdrop_trigger.settings.entity");
    $values = $form_state->getValues();

    $config->set("enabled", (bool) ($values["enabled"] ?? TRUE));

    // Process event types from nested structure.
    $eventTypesWrapper = $values["event_types_wrapper"] ?? [];
    $allowedEventTypes = $this->filterCheckboxValues(
      $eventTypesWrapper["allowed_event_types"] ?? []
    );
    $config->set("allowed_event_types", $allowedEventTypes);

    // Process entity types from nested structure.
    $entityTypesWrapper = $values["entity_types_wrapper"] ?? [];
    $allowedEntityTypes = $this->filterCheckboxValues(
      $entityTypesWrapper["allowed_entity_types"] ?? []
    );
    $config->set("allowed_entity_types", $allowedEntityTypes);

    // Process bundles from nested structure.
    $bundlesWrapper = $values["bundles_wrapper"] ?? [];
    $allowedBundles = $this->filterCheckboxValues(
      $bundlesWrapper["allowed_bundles"] ?? []
    );
    $config->set("allowed_bundles", $allowedBundles);

    // Process additional options from nested structure.
    $options = $values["options"] ?? [];
    $config->set("log_entity_changes", (bool) ($options["log_entity_changes"] ?? FALSE));

    $config->save();

    parent::submitForm($form, $form_state);
  }

  /**
   * Get content entity type options for the form.
   *
   * @return array<string, string>
   *   Array of entity type options keyed by entity type ID.
   */
  protected function getContentEntityTypeOptions(): array {
    $options = [];
    $entityTypeDefinitions = $this->entityTypeManager->getDefinitions();

    foreach ($entityTypeDefinitions as $entityTypeId => $entityType) {
      // Only include content entities (not config entities).
      if ($entityType->getGroup() === "content") {
        $label = $entityType->getLabel();
        $options[$entityTypeId] = $label instanceof \Stringable ? (string) $label : $entityTypeId;
      }
    }

    asort($options);
    return $options;
  }

  /**
   * Get bundle options grouped by entity type.
   *
   * @return array<string, string>
   *   Array of bundle options keyed by entity_type:bundle format.
   */
  protected function getBundleOptions(): array {
    $options = [];
    $entityTypeDefinitions = $this->entityTypeManager->getDefinitions();

    foreach ($entityTypeDefinitions as $entityTypeId => $entityType) {
      if ($entityType->getGroup() !== "content") {
        continue;
      }

      $entityTypeLabel = $entityType->getLabel();
      $entityTypeLabelString = $entityTypeLabel instanceof \Stringable
        ? (string) $entityTypeLabel
        : $entityTypeId;

      $bundles = $this->bundleInfo->getBundleInfo($entityTypeId);

      foreach ($bundles as $bundleId => $bundleInfo) {
        $bundleLabel = $bundleInfo["label"] ?? $bundleId;
        $bundleLabelString = $bundleLabel instanceof \Stringable
          ? (string) $bundleLabel
          : $bundleId;

        $key = sprintf("%s:%s", $entityTypeId, $bundleId);
        $options[$key] = sprintf("%s: %s", $entityTypeLabelString, $bundleLabelString);
      }
    }

    asort($options);
    return $options;
  }

}
