<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\DTO;

/**
 * Data transfer object representing interrupt state.
 *
 * This class holds all the data needed to resume a workflow after an interrupt
 * has been resolved.
 *
 * @api
 */
final class InterruptState {

  /**
   * Interrupt status: pending resolution.
   */
  public const STATUS_PENDING = 'pending';

  /**
   * Interrupt status: resolved by user.
   */
  public const STATUS_RESOLVED = 'resolved';

  /**
   * Interrupt status: expired or cancelled.
   */
  public const STATUS_EXPIRED = 'expired';

  /**
   * Constructs a new InterruptState.
   *
   * @param string $interruptId
   *   The unique interrupt ID.
   * @param string $interruptType
   *   The type of interrupt (e.g., 'human_input', 'approval').
   * @param string $pipelineId
   *   The pipeline ID.
   * @param string $jobId
   *   The interrupted job ID.
   * @param string $nodeId
   *   The node ID where the interrupt occurred.
   * @param string $executionId
   *   The execution ID.
   * @param string $workflowId
   *   The workflow ID.
   * @param array $interruptData
   *   Additional interrupt data (prompt, options, etc.).
   * @param array $executionContext
   *   The execution context at the time of interrupt.
   * @param array $partialResults
   *   Partial results collected before the interrupt.
   * @param string $status
   *   The interrupt status.
   * @param array|null $userInput
   *   The user input that resolves the interrupt (if resolved).
   * @param int $createdAt
   *   Timestamp when the interrupt was created.
   * @param int|null $resolvedAt
   *   Timestamp when the interrupt was resolved (if resolved).
   */
  public function __construct(
    public readonly string $interruptId,
    public readonly string $interruptType,
    public readonly string $pipelineId,
    public readonly string $jobId,
    public readonly string $nodeId,
    public readonly string $executionId,
    public readonly string $workflowId,
    public readonly array $interruptData,
    public readonly array $executionContext,
    public readonly array $partialResults,
    public readonly string $status = self::STATUS_PENDING,
    public readonly ?array $userInput = NULL,
    public readonly int $createdAt = 0,
    public readonly ?int $resolvedAt = NULL,
  ) {
  }

  /**
   * Creates an InterruptState from an array.
   *
   * @param array $data
   *   The data array.
   *
   * @return static
   *   The InterruptState instance.
   */
  public static function fromArray(array $data): static {
    return new static(
      interruptId: $data['interrupt_id'] ?? '',
      interruptType: $data['interrupt_type'] ?? '',
      pipelineId: $data['pipeline_id'] ?? '',
      jobId: $data['job_id'] ?? '',
      nodeId: $data['node_id'] ?? '',
      executionId: $data['execution_id'] ?? '',
      workflowId: $data['workflow_id'] ?? '',
      interruptData: $data['interrupt_data'] ?? [],
      executionContext: $data['execution_context'] ?? [],
      partialResults: $data['partial_results'] ?? [],
      status: $data['status'] ?? self::STATUS_PENDING,
      userInput: $data['user_input'] ?? NULL,
      createdAt: $data['created_at'] ?? 0,
      resolvedAt: $data['resolved_at'] ?? NULL,
    );
  }

  /**
   * Converts the InterruptState to an array.
   *
   * @return array
   *   The array representation.
   */
  public function toArray(): array {
    return [
      'interrupt_id' => $this->interruptId,
      'interrupt_type' => $this->interruptType,
      'pipeline_id' => $this->pipelineId,
      'job_id' => $this->jobId,
      'node_id' => $this->nodeId,
      'execution_id' => $this->executionId,
      'workflow_id' => $this->workflowId,
      'interrupt_data' => $this->interruptData,
      'execution_context' => $this->executionContext,
      'partial_results' => $this->partialResults,
      'status' => $this->status,
      'user_input' => $this->userInput,
      'created_at' => $this->createdAt,
      'resolved_at' => $this->resolvedAt,
    ];
  }

  /**
   * Creates a resolved version of this interrupt state.
   *
   * @param array $userInput
   *   The user input that resolves the interrupt.
   *
   * @return static
   *   A new InterruptState with resolved status.
   */
  public function withResolution(array $userInput): static {
    return new static(
      interruptId: $this->interruptId,
      interruptType: $this->interruptType,
      pipelineId: $this->pipelineId,
      jobId: $this->jobId,
      nodeId: $this->nodeId,
      executionId: $this->executionId,
      workflowId: $this->workflowId,
      interruptData: $this->interruptData,
      executionContext: $this->executionContext,
      partialResults: $this->partialResults,
      status: self::STATUS_RESOLVED,
      userInput: $userInput,
      createdAt: $this->createdAt,
      resolvedAt: time(),
    );
  }

  /**
   * Checks if the interrupt is pending.
   *
   * @return bool
   *   TRUE if pending.
   */
  public function isPending(): bool {
    return $this->status === self::STATUS_PENDING;
  }

  /**
   * Checks if the interrupt is resolved.
   *
   * @return bool
   *   TRUE if resolved.
   */
  public function isResolved(): bool {
    return $this->status === self::STATUS_RESOLVED;
  }

}
