<?php

declare(strict_types=1);

namespace Drupal\flowdrop_workflow_executor\Service;

use Drupal\flowdrop_workflow_executor\DTO\WorkflowExecutionResult;
use Drupal\flowdrop_workflow_executor\Enum\WorkflowExecutionMode;
use Drupal\flowdrop_workflow_executor\Enum\WorkflowExecutionStatus;
use Drupal\flowdrop_workflow\WorkflowDefinitionInterface;

/**
 * Interface for the workflow execution service.
 *
 * This service provides methods to execute FlowDrop workflows programmatically,
 * supporting various execution modes including synchronous job-based execution,
 * async execution, and fire-and-forget patterns.
 *
 * @api
 */
interface WorkflowExecutionServiceInterface {

  /**
   * Executes a workflow with the specified mode.
   *
   * @param \Drupal\flowdrop_workflow\WorkflowDefinitionInterface $workflow
   *   The workflow to execute.
   * @param array<string, mixed> $inputData
   *   Input data to pass to the workflow.
   * @param \Drupal\flowdrop_workflow_executor\Enum\WorkflowExecutionMode $mode
   *   Execution mode.
   * @param int $timeout
   *   Timeout in seconds for 'job' mode (default: 300).
   * @param int $pollIntervalMs
   *   Polling interval in milliseconds (default: 2000).
   * @param array<string, mixed> $parentContext
   *   Parent workflow context for recursion tracking.
   *
   * @return \Drupal\flowdrop_workflow_executor\DTO\WorkflowExecutionResult
   *   The execution result.
   */
  public function execute(
    WorkflowDefinitionInterface $workflow,
    array $inputData = [],
    WorkflowExecutionMode $mode = WorkflowExecutionMode::Job,
    int $timeout = 300,
    int $pollIntervalMs = 2000,
    array $parentContext = [],
  ): WorkflowExecutionResult;

  /**
   * Gets results for an existing session.
   *
   * @param string $sessionId
   *   The session ID to get results for.
   * @param bool $waitForCompletion
   *   Whether to wait for completion.
   * @param int $timeout
   *   Timeout in seconds.
   * @param int $pollIntervalMs
   *   Polling interval in milliseconds.
   *
   * @return \Drupal\flowdrop_workflow_executor\DTO\WorkflowExecutionResult
   *   The execution result.
   */
  public function getResults(
    string $sessionId,
    bool $waitForCompletion = TRUE,
    int $timeout = 300,
    int $pollIntervalMs = 2000,
  ): WorkflowExecutionResult;

  /**
   * Checks if a workflow session has completed.
   *
   * @param string $sessionId
   *   The session ID.
   *
   * @return bool
   *   TRUE if completed, FALSE otherwise.
   */
  public function isComplete(string $sessionId): bool;

  /**
   * Gets the current status of a workflow session.
   *
   * @param string $sessionId
   *   The session ID.
   *
   * @return \Drupal\flowdrop_workflow_executor\Enum\WorkflowExecutionStatus
   *   The execution status.
   */
  public function getStatus(string $sessionId): WorkflowExecutionStatus;

  /**
   * Cancels an in-flight sub-workflow execution by session id.
   *
   * Resolves the most-recent active sub-pipeline for the session
   * (via the pipeline.session_id reverse-lookup) and delegates to
   * {@see ::cancelPipeline()}. Kept for back-compat with older
   * WorkflowExecution interrupt entries that only stamped
   * sub_session_id; new dispatches stamp sub_pipeline_id and should
   * call cancelPipeline directly.
   *
   * Best-effort: returns FALSE if no in-flight sub-pipeline is found.
   *
   * @param string $sessionId
   *   The sub-workflow's session ID. With shared sessions this is the
   *   parent's session — the reverse-lookup filters to pipelines whose
   *   workflow differs from the session's primary workflow.
   * @param string|null $reason
   *   Reason string surfaced to the sub-pipeline's audit log.
   * @param int|null $initiatorUid
   *   The user who initiated the parent's cancellation, if known.
   *
   * @return bool
   *   TRUE if a Cancel signal was created on a sub-pipeline.
   */
  public function cancelExecution(
    string $sessionId,
    ?string $reason = NULL,
    ?int $initiatorUid = NULL,
  ): bool;

  /**
   * Extracts outputs from a completed pipeline by id.
   *
   * Reads completed-job outputs directly from the pipeline entity —
   * decoupled from session status. Required for the cascade resolve
   * path: when a sub-pipeline finishes inside a shared parent session,
   * the session stays RUNNING (the parent is still mid-execution), so
   * a session-status check would report no outputs available even
   * though the sub's outputs are ready on its pipeline entity.
   *
   * @param string $pipelineId
   *   The completed sub-pipeline's id.
   *
   * @return array<string, mixed>
   *   Map of node id → output data for that pipeline's completed jobs.
   *   Empty array if the pipeline can't be loaded.
   */
  public function getPipelineOutputs(string $pipelineId): array;

  /**
   * Cancels an in-flight sub-workflow execution by pipeline id.
   *
   * Creates a Cancel inward signal on the target pipeline. The
   * orchestrator picks it up on its next job-loop iteration and tears
   * down, which itself may cascade to deeper sub-workflows.
   *
   * Preferred entry point for cascade cancels: when a parent's
   * WorkflowExecution interrupt context stamps `sub_pipeline_id` the
   * cancel targets that pipeline directly, without relying on a
   * session→pipeline lookup that no longer holds in shared-session mode.
   *
   * @param string $pipelineId
   *   The sub-pipeline's id (stamped on the WorkflowExecution
   *   interrupt context as `sub_pipeline_id`).
   * @param string|null $reason
   *   Reason string surfaced to the sub-pipeline's audit log.
   * @param int|null $initiatorUid
   *   The user who initiated the parent's cancellation, if known.
   *
   * @return bool
   *   TRUE if a Cancel signal was created on the sub-pipeline; FALSE if
   *   a signal was already pending or the message bus is unavailable.
   */
  public function cancelPipeline(
    string $pipelineId,
    ?string $reason = NULL,
    ?int $initiatorUid = NULL,
  ): bool;

}
