<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Service;

use Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface;

/**
 * Full interrupt management surface.
 *
 * Composes the narrower {@see InterruptRepositoryInterface}
 * (read-only queries) and
 * {@see InterruptFactoryInterface} (create-side), adding
 * lifecycle transitions (resolve / cancel / expire / cleanup) and bulk
 * operations on top.
 *
 * Consumers that only query interrupts should type-hint
 * `InterruptRepositoryInterface`. Code that only creates them should
 * type-hint `InterruptFactoryInterface`. Code that drives the full
 * lifecycle (the orchestrator catch site, the HTTP resolve controller)
 * keeps using this composite interface.
 *
 * @api
 */
interface InterruptManagerInterface extends InterruptRepositoryInterface, InterruptFactoryInterface {

  /**
   * 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;

  /**
   * Cancels an interrupt.
   *
   * @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.
   *
   * @return int
   *   The number of interrupts cancelled.
   */
  public function cancelInterruptsForSession(int $session_id): int;

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

  /**
   * Cancels all pending outward interrupts on a pipeline.
   *
   * Called by the orchestrator's Cancel handler so pending HITL prompts
   * on a cancelled pipeline don't sit forever in the inbox.
   *
   * @return int
   *   The number of interrupts cancelled.
   */
  public function cancelOutwardInterruptsForPipeline(string $pipelineId): int;

  /**
   * Expires all overdue pending interrupts.
   *
   * @param int|null $limit
   *   Maximum number of interrupts to process in this call. NULL or <= 0
   *   means unbounded — only use that from one-shot CLI/admin contexts.
   *   Cron callers should keep the default cap so a backlog drains over
   *   multiple runs rather than OOMing on one.
   *
   * @return int
   *   The number of interrupts expired.
   */
  public function expireOverdueInterrupts(?int $limit = 500): int;

  /**
   * Cleans up old resolved/cancelled/expired interrupts.
   *
   * @param int $max_age
   *   Maximum age in seconds for interrupts to keep.
   * @param int|null $limit
   *   Maximum number of interrupts to delete in this call. See
   *   {@see self::expireOverdueInterrupts()} for the rationale on bounding.
   *
   * @return int
   *   The number of interrupts deleted.
   */
  public function cleanupOldInterrupts(int $max_age, ?int $limit = 500): int;

}
