<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Service;

use Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface;
use Drupal\flowdrop_interrupt\Enum\InterruptType;

/**
 * Interface for the Interrupt Manager service.
 *
 * The Interrupt Manager handles the lifecycle of interrupt requests,
 * including creation, resolution, querying, and cleanup.
 *
 * @api
 */
interface InterruptManagerInterface {

  /**
   * Creates a new interrupt request.
   *
   * @param \Drupal\flowdrop_interrupt\Enum\InterruptType $type
   *   The type of interrupt.
   * @param string $workflow_id
   *   The workflow ID.
   * @param string $node_id
   *   The node ID that triggered the interrupt.
   * @param string $message
   *   The message to display to the user.
   * @param array<string, mixed> $schema
   *   JSON Schema for input validation (optional).
   * @param array<int, array{value: string, label: string, description?: string}> $options
   *   Options for choice-type interrupts (optional).
   * @param array<string, mixed> $context
   *   Execution context for resuming the workflow.
   * @param mixed $default_value
   *   Default value for the input (optional).
   * @param string|null $pipeline_id
   *   Pipeline/execution ID (optional).
   * @param int|null $session_id
   *   Playground session ID (optional).
   * @param int|null $expires_in
   *   Seconds until expiration (optional, 0 or NULL for no expiration).
   *
   * @return \Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface
   *   The created interrupt entity.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   *   If the entity cannot be saved.
   */
  public function createInterrupt(
    InterruptType $type,
    string $workflow_id,
    string $node_id,
    string $message,
    array $schema = [],
    array $options = [],
    array $context = [],
    mixed $default_value = NULL,
    ?string $pipeline_id = NULL,
    ?int $session_id = NULL,
    ?int $expires_in = NULL,
  ): FlowDropInterruptInterface;

  /**
   * Resolves an interrupt with user input.
   *
   * @param string $interrupt_id
   *   The interrupt UUID.
   * @param mixed $response_data
   *   The user's response data.
   * @param int|null $user_id
   *   The user ID who resolved (optional).
   *
   * @return \Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface|null
   *   The resolved interrupt entity, or NULL if not found or already resolved.
   *
   * @throws \InvalidArgumentException
   *   If the interrupt is not in a resolvable state.
   */
  public function resolveInterrupt(
    string $interrupt_id,
    mixed $response_data,
    ?int $user_id = NULL,
  ): ?FlowDropInterruptInterface;

  /**
   * Gets an interrupt by UUID.
   *
   * @param string $interrupt_id
   *   The interrupt UUID.
   *
   * @return \Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface|null
   *   The interrupt entity or NULL if not found.
   */
  public function getInterrupt(string $interrupt_id): ?FlowDropInterruptInterface;

  /**
   * Gets pending interrupts for a session.
   *
   * @param int $session_id
   *   The playground session ID.
   *
   * @return array<\Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface>
   *   Array of pending interrupt entities.
   */
  public function getPendingInterruptsForSession(int $session_id): array;

  /**
   * Gets pending interrupts for a pipeline.
   *
   * @param string $pipeline_id
   *   The pipeline/execution ID.
   *
   * @return array<\Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface>
   *   Array of pending interrupt entities.
   */
  public function getPendingInterruptsForPipeline(string $pipeline_id): array;

  /**
   * Gets pending interrupts for a workflow.
   *
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return array<\Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface>
   *   Array of pending interrupt entities.
   */
  public function getPendingInterruptsForWorkflow(string $workflow_id): array;

  /**
   * Checks if there are pending interrupts for a session.
   *
   * @param int $session_id
   *   The session ID.
   *
   * @return bool
   *   TRUE if there are pending interrupts.
   */
  public function hasPendingInterruptsForSession(int $session_id): bool;

  /**
   * Checks if there are pending interrupts for a pipeline.
   *
   * @param string $pipeline_id
   *   The pipeline ID.
   *
   * @return bool
   *   TRUE if there are pending interrupts.
   */
  public function hasPendingInterruptsForPipeline(string $pipeline_id): bool;

  /**
   * Cancels an interrupt.
   *
   * @param string $interrupt_id
   *   The interrupt UUID.
   *
   * @return bool
   *   TRUE if successfully cancelled, FALSE if not found or not pending.
   */
  public function cancelInterrupt(string $interrupt_id): bool;

  /**
   * Cancels all pending interrupts for a session.
   *
   * @param int $session_id
   *   The session ID.
   *
   * @return int
   *   The number of interrupts cancelled.
   */
  public function cancelInterruptsForSession(int $session_id): int;

  /**
   * Cancels all pending interrupts for a pipeline.
   *
   * @param string $pipeline_id
   *   The pipeline ID.
   *
   * @return int
   *   The number of interrupts cancelled.
   */
  public function cancelInterruptsForPipeline(string $pipeline_id): int;

  /**
   * Expires all overdue pending interrupts.
   *
   * @return int
   *   The number of interrupts expired.
   */
  public function expireOverdueInterrupts(): int;

  /**
   * Cleans up old resolved/cancelled/expired interrupts.
   *
   * @param int $max_age
   *   Maximum age in seconds for interrupts to keep.
   *
   * @return int
   *   The number of interrupts deleted.
   */
  public function cleanupOldInterrupts(int $max_age): int;

  /**
   * Gets a resolved interrupt for a specific node in a pipeline.
   *
   * This is used when resuming workflow execution after an interrupt
   * has been resolved. The node processor can use this to retrieve
   * the user's response data.
   *
   * @param string $pipeline_id
   *   The pipeline/execution ID.
   * @param string $node_id
   *   The node ID that created the interrupt.
   *
   * @return \Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface|null
   *   The resolved interrupt entity, or NULL if not found.
   */
  public function getResolvedInterruptForNode(string $pipeline_id, string $node_id): ?FlowDropInterruptInterface;

}
