<?php

declare(strict_types=1);

namespace Drupal\flowdrop_trigger\Plugin\Validation\Constraint;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\flowdrop_trigger\FlowDropTriggerConfigInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the UniqueWorkflowNodeCombination constraint.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class UniqueWorkflowNodeCombinationConstraintValidator extends ConstraintValidator {

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

  /**
   * Constructs a new validator instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get("entity_type.manager")
    );
  }

  /**
   * {@inheritdoc}
   */
  public function validate($entity, Constraint $constraint): void {
    if (!$entity instanceof FlowDropTriggerConfigInterface) {
      return;
    }

    $workflowId = $entity->getWorkflowId();
    $nodeId = $entity->getNodeId();

    // Skip validation if either value is empty.
    if (empty($workflowId) || empty($nodeId)) {
      return;
    }

    $entityId = $entity->id();
    $storage = $this->entityTypeManager->getStorage("flowdrop_trigger_config");

    if (!$storage instanceof EntityStorageInterface) {
      return;
    }

    // Query for existing entities with the same workflow_id and node_id.
    $query = $storage->getQuery()
      // Access bypassed: validation must check all
      // entities regardless of current user.
      ->accessCheck(FALSE)
      ->condition("workflow_id", $workflowId)
      ->condition("node_id", $nodeId);

    // Exclude the current entity if it exists.
    if (!empty($entityId)) {
      $query->condition("id", $entityId, "<>");
    }

    $result = $query->execute();

    // If we found a match, add a violation.
    if (!empty($result)) {
      $this->context->addViolation($constraint->message, [
        "%workflow_id" => $workflowId,
        "%node_id" => $nodeId,
      ]);
    }
  }

}
