<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Entity;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\flowdrop_interrupt\Enum\InterruptDirection;
use Drupal\flowdrop_interrupt\Enum\InterruptStatus;
use Drupal\flowdrop_interrupt\Enum\InterruptType;
use Drupal\flowdrop_orchestration\DTO\ResolvedInterruptInterface;
use Drupal\user\EntityOwnerInterface;

/**
 * Interface for FlowDrop Interrupt entities.
 *
 * Interrupt entities store requests for human input during workflow execution.
 * They persist the interrupt state, allowing workflows to pause and resume
 * after user interaction.
 *
 * @api
 */
interface FlowDropInterruptInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface, ResolvedInterruptInterface {

  /**
   * Gets the workflow ID.
   *
   * @return string
   *   The workflow ID.
   */
  public function getWorkflowId(): string;

  /**
   * Sets the workflow ID.
   *
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return $this
   */
  public function setWorkflowId(string $workflow_id): static;

  /**
   * Gets the pipeline/execution ID.
   *
   * @return string|null
   *   The pipeline ID or NULL if not associated with a pipeline.
   */
  public function getPipelineId(): ?string;

  /**
   * Sets the pipeline/execution ID.
   *
   * @param string|null $pipeline_id
   *   The pipeline ID.
   *
   * @return $this
   */
  public function setPipelineId(?string $pipeline_id): static;

  /**
   * Gets the playground session ID.
   *
   * @return int|null
   *   The session ID or NULL if not associated with a session.
   */
  public function getSessionId(): ?int;

  /**
   * Sets the playground session ID.
   *
   * @param int|null $session_id
   *   The session ID.
   *
   * @return $this
   */
  public function setSessionId(?int $session_id): static;

  /**
   * Gets the node ID that triggered the interrupt.
   *
   * @return string
   *   The node ID.
   */
  public function getNodeId(): string;

  /**
   * Sets the node ID.
   *
   * @param string $node_id
   *   The node ID.
   *
   * @return $this
   */
  public function setNodeId(string $node_id): static;

  /**
   * Gets the interrupt type.
   *
   * @return \Drupal\flowdrop_interrupt\Enum\InterruptType
   *   The interrupt type.
   */
  public function getType(): InterruptType;

  /**
   * Sets the interrupt type.
   *
   * @param \Drupal\flowdrop_interrupt\Enum\InterruptType $type
   *   The interrupt type.
   *
   * @return $this
   */
  public function setType(InterruptType $type): static;

  /**
   * Gets the interrupt status.
   *
   * @return \Drupal\flowdrop_interrupt\Enum\InterruptStatus
   *   The interrupt status.
   */
  public function getStatus(): InterruptStatus;

  /**
   * Sets the interrupt status.
   *
   * @param \Drupal\flowdrop_interrupt\Enum\InterruptStatus $status
   *   The interrupt status.
   *
   * @return $this
   */
  public function setStatus(InterruptStatus $status): static;

  /**
   * Gets the display message.
   *
   * @return string
   *   The message to display to the user.
   */
  public function getMessage(): string;

  /**
   * Sets the display message.
   *
   * @param string $message
   *   The message.
   *
   * @return $this
   */
  public function setMessage(string $message): static;

  /**
   * Gets the JSON Schema for input validation.
   *
   * @return array<string, mixed>
   *   The JSON Schema or empty array if not set.
   */
  public function getSchema(): array;

  /**
   * Sets the JSON Schema for input validation.
   *
   * @param array<string, mixed> $schema
   *   The JSON Schema.
   *
   * @return $this
   */
  public function setSchema(array $schema): static;

  /**
   * Gets the options for choice-type interrupts.
   *
   * @return array<int, array{value: string, label: string, description?: string}>
   *   The options array.
   */
  public function getOptions(): array;

  /**
   * Sets the options for choice-type interrupts.
   *
   * @param array<int, array{value: string, label: string, description?: string}> $options
   *   The options array.
   *
   * @return $this
   */
  public function setOptions(array $options): static;

  /**
   * Gets the default value.
   *
   * @return mixed
   *   The default value.
   */
  public function getDefaultValue(): mixed;

  /**
   * Sets the default value.
   *
   * @param mixed $value
   *   The default value.
   *
   * @return $this
   */
  public function setDefaultValue(mixed $value): static;

  /**
   * Gets the user's response data.
   *
   * @return mixed
   *   The response data or NULL if not resolved.
   */
  public function getResponseData(): mixed;

  /**
   * Sets the user's response data.
   *
   * @param mixed $data
   *   The response data.
   *
   * @return $this
   */
  public function setResponseData(mixed $data): static;

  /**
   * Gets the execution context for resuming the workflow.
   *
   * @return array<string, mixed>
   *   The execution context.
   */
  public function getContext(): array;

  /**
   * Sets the execution context.
   *
   * @param array<string, mixed> $context
   *   The execution context.
   *
   * @return $this
   */
  public function setContext(array $context): static;

  /**
   * Gets the expiration timestamp.
   *
   * @return int|null
   *   The expiration timestamp or NULL if no expiration.
   */
  public function getExpires(): ?int;

  /**
   * Sets the expiration timestamp.
   *
   * @param int|null $timestamp
   *   The expiration timestamp.
   *
   * @return $this
   */
  public function setExpires(?int $timestamp): static;

  /**
   * Gets the scheduled-resolution timestamp.
   *
   * Only set on scheduled interrupts (e.g. Timer): the time at which the
   * cron sweep automatically resolves the interrupt. Distinct from
   * expiration — a due scheduled interrupt is resolved (the pipeline
   * resumes), an expired one is discarded.
   *
   * @return int|null
   *   The scheduled timestamp, or NULL when not a scheduled interrupt.
   */
  public function getScheduledAt(): ?int;

  /**
   * Sets the scheduled-resolution timestamp.
   *
   * @param int|null $timestamp
   *   The scheduled timestamp, or NULL/0 to unset.
   *
   * @return $this
   */
  public function setScheduledAt(?int $timestamp): static;

  /**
   * Gets the user ID who resolved the interrupt.
   *
   * @return int|null
   *   The user ID or NULL if not resolved.
   */
  public function getResolvedBy(): ?int;

  /**
   * Sets the user ID who resolved the interrupt.
   *
   * @param int|null $user_id
   *   The user ID.
   *
   * @return $this
   */
  public function setResolvedBy(?int $user_id): static;

  /**
   * Gets the resolution timestamp.
   *
   * @return int|null
   *   The timestamp or NULL if not resolved.
   */
  public function getResolvedAt(): ?int;

  /**
   * Sets the resolution timestamp.
   *
   * @param int|null $timestamp
   *   The timestamp.
   *
   * @return $this
   */
  public function setResolvedAt(?int $timestamp): static;

  /**
   * Gets the creation timestamp.
   *
   * @return int
   *   The creation timestamp.
   */
  public function getCreatedTime(): int;

  /**
   * Gets the last changed timestamp.
   *
   * @return int
   *   The changed timestamp.
   */
  public function getChangedTime(): int;

  /**
   * Checks if the interrupt is pending.
   *
   * @return bool
   *   TRUE if pending.
   */
  public function isPending(): bool;

  /**
   * Checks if the interrupt is resolved.
   *
   * @return bool
   *   TRUE if resolved.
   */
  public function isResolved(): bool;

  /**
   * Checks if the interrupt has expired.
   *
   * @return bool
   *   TRUE if expired.
   */
  public function isExpired(): bool;

  /**
   * Resolves the interrupt with the given response data.
   *
   * @param mixed $response_data
   *   The user's response.
   * @param int|null $user_id
   *   The user ID who resolved it.
   *
   * @return $this
   */
  public function resolve(mixed $response_data, ?int $user_id = NULL): static;

  /**
   * Cancels the interrupt.
   *
   * @return $this
   */
  public function cancel(): static;

  /**
   * Marks the interrupt as expired.
   *
   * @return $this
   */
  public function expire(): static;

  /**
   * Converts the interrupt to an array for API responses.
   *
   * @return array<string, mixed>
   *   The interrupt data as an array.
   */
  public function toApiArray(): array;

  /**
   * Gets the direction of this interrupt.
   *
   * Outward interrupts are raised by a node inside a running pipeline and
   * wait for external resolution. Inward interrupts target a pipeline from
   * outside (Cancel / Pause signals).
   *
   * @return \Drupal\flowdrop_interrupt\Enum\InterruptDirection
   *   The direction. Defaults to Outward when not set (legacy rows).
   */
  public function getDirection(): InterruptDirection;

  /**
   * Sets the direction of this interrupt.
   *
   * @return $this
   */
  public function setDirection(InterruptDirection $direction): static;

  /**
   * Gets the job entity ID that owns this interrupt, if any.
   *
   * Set by the orchestrator when persisting an outward interrupt so that
   * the resume path can locate the interrupted job in O(1) instead of
   * scanning the pipeline's job list.
   *
   * @return int|null
   *   The job entity ID, or NULL for inward signals and legacy rows that
   *   haven't been backfilled.
   */
  public function getJobId(): ?int;

  /**
   * Sets the owning job entity ID.
   *
   * @return $this
   */
  public function setJobId(?int $job_id): static;

  /**
   * Gets the target pipeline ID for inward signals.
   *
   * For inward signals (Cancel, Pause) the pipeline this interrupt acts
   * ON — distinct from `pipeline_id`, which is the pipeline that owns the
   * interrupt. Outward interrupts have NULL here.
   *
   * @return string|null
   *   The pipeline ID, or NULL for outward interrupts.
   */
  public function getTargetPipelineId(): ?string;

  /**
   * Sets the target pipeline ID.
   *
   * @return $this
   */
  public function setTargetPipelineId(?string $pipeline_id): static;

  /**
   * Gets the UID that initiated this signal (audit trail for inward signals).
   *
   * @return int|null
   *   The initiator UID, or NULL.
   */
  public function getInitiatorUid(): ?int;

  /**
   * Sets the initiator UID.
   *
   * @return $this
   */
  public function setInitiatorUid(?int $uid): static;

  /**
   * Gets the free-form reason the initiator gave when raising this signal.
   *
   * @return string|null
   *   The reason, or NULL.
   */
  public function getReason(): ?string;

  /**
   * Sets the reason.
   *
   * @return $this
   */
  public function setReason(?string $reason): static;

  /**
   * Gets the UUID of the interrupt this one is gated on, if any.
   *
   * When set, the cascade subscriber resolves this interrupt with the
   * linked interrupt's response_data when the linked one resolves.
   *
   * @return string|null
   *   The linked interrupt UUID, or NULL when this interrupt is independent.
   */
  public function getLinkedInterruptId(): ?string;

  /**
   * Sets the linked interrupt UUID.
   *
   * @return $this
   */
  public function setLinkedInterruptId(?string $linked_interrupt_id): static;

  /**
   * Gets the pipeline this interrupt acts on, regardless of direction.
   *
   * For outward interrupts returns `pipeline_id`. For inward signals
   * returns `target_pipeline_id`. Subscribers that need "which pipeline
   * should I act on?" should use this rather than picking the right
   * field by direction.
   *
   * @return string|null
   *   The pipeline ID, or NULL when the interrupt doesn't target a pipeline.
   */
  public function getEffectivePipelineId(): ?string;

  /**
   * Marks the interrupt as acknowledged (for inward signals).
   *
   * Distinct from {@see self::resolve()} which writes response_data.
   * Inward signals don't have a user response — they're acted on by the
   * orchestrator and acknowledged when done.
   *
   * @return $this
   */
  public function acknowledge(): static;

}
