<?php

declare(strict_types=1);

namespace Drupal\flowdrop\DTO;

/**
 * Data Transfer Object for workflow execution context.
 *
 * This DTO provides type-safe access to workflow execution context data.
 * Processors that implement ExecutionContextAwareInterface receive an
 * instance of this class before execution.
 *
 * The context includes:
 * - Initial data passed when workflow execution started
 * - Workflow, pipeline, and execution identifiers
 * - Additional metadata about the current execution
 *
 * @see \Drupal\flowdrop\Plugin\FlowDropNodeProcessor\ExecutionContextAwareInterface
 */
final class ExecutionContextDTO {

  /**
   * Constructs an ExecutionContextDTO.
   *
   * @param array<string, mixed> $initialData
   *   The initial data passed when workflow execution started.
   * @param string $workflowId
   *   The workflow ID being executed.
   * @param string $pipelineId
   *   The pipeline ID being executed.
   * @param string $executionId
   *   The unique execution identifier.
   * @param string $nodeId
   *   The id of the node being executed.
   * @param array<string, mixed> $metadata
   *   Additional execution metadata.
   */
  public function __construct(
    private readonly array $initialData,
    private readonly string $workflowId,
    private readonly string $pipelineId,
    private readonly string $executionId,
    private readonly string $nodeId,
    private readonly array $metadata = [],
  ) {}

  /**
   * Gets the node id.
   *
   * @return string
   *   The node id.
   */
  public function getNodeId(): string {
    return $this->nodeId;
  }

  /**
   * Gets the initial data passed when workflow execution started.
   *
   * This is the data provided by triggers (webhook payload, form data, etc.)
   * or passed programmatically when starting the workflow.
   *
   * @return array<string, mixed>
   *   The initial workflow data.
   */
  public function getInitialData(): array {
    return $this->initialData;
  }

  /**
   * Gets a specific value from the initial data.
   *
   * @param string $key
   *   The key to retrieve.
   * @param mixed $default
   *   Default value if key doesn't exist.
   *
   * @return mixed
   *   The value or default.
   */
  public function getInitialDataValue(string $key, mixed $default = NULL): mixed {
    return $this->initialData[$key] ?? $default;
  }

  /**
   * Checks if initial data has a specific key.
   *
   * @param string $key
   *   The key to check.
   *
   * @return bool
   *   TRUE if the key exists.
   */
  public function hasInitialDataKey(string $key): bool {
    return array_key_exists($key, $this->initialData);
  }

  /**
   * Gets the workflow ID being executed.
   *
   * @return string
   *   The workflow ID.
   */
  public function getWorkflowId(): string {
    return $this->workflowId;
  }

  /**
   * Gets the pipeline ID being executed.
   *
   * @return string
   *   The pipeline ID.
   */
  public function getPipelineId(): string {
    return $this->pipelineId;
  }

  /**
   * Gets the unique execution identifier.
   *
   * This ID is unique per workflow execution run.
   *
   * @return string
   *   The execution ID.
   */
  public function getExecutionId(): string {
    return $this->executionId;
  }

  /**
   * Gets additional execution metadata.
   *
   * @return array<string, mixed>
   *   The metadata array.
   */
  public function getMetadata(): array {
    return $this->metadata;
  }

  /**
   * Gets a specific metadata value.
   *
   * @param string $key
   *   The metadata key.
   * @param mixed $default
   *   Default value if key doesn't exist.
   *
   * @return mixed
   *   The metadata value or default.
   */
  public function getMetadataValue(string $key, mixed $default = NULL): mixed {
    return $this->metadata[$key] ?? $default;
  }

  /**
   * Creates an ExecutionContextDTO from an array.
   *
   * @param array<string, mixed> $data
   *   The context data array with keys:
   *   - initial_data: array
   *   - workflow_id: string
   *   - pipeline_id: string
   *   - execution_id: string
   *   - metadata: array (optional)
   *
   * @return self
   *   A new ExecutionContextDTO instance.
   */
  public static function fromArray(array $data): self {
    return new self(
      initialData: $data["initial_data"] ?? [],
      workflowId: $data["workflow_id"] ?? "",
      pipelineId: $data["pipeline_id"] ?? "",
      executionId: $data["execution_id"] ?? "",
      nodeId: $data["node_id"] ?? "",
      metadata: $data["metadata"] ?? [],
    );
  }

  /**
   * Converts the DTO to an array.
   *
   * @return array<string, mixed>
   *   The context as an array.
   */
  public function toArray(): array {
    return [
      "initial_data" => $this->initialData,
      "workflow_id" => $this->workflowId,
      "pipeline_id" => $this->pipelineId,
      "execution_id" => $this->executionId,
      "metadata" => $this->metadata,
    ];
  }

}
