<?php

namespace Drupal\acquia_contenthub\Libs\ServiceQueue;

use Drupal\Component\Serialization\Json;

/**
 * Represents a service queue item for Content Hub syndication.
 *
 * This class encapsulates the structure and behavior of service queue items
 * used in Content Hub pull syndication operations.
 *
 * @package Drupal\acquia_contenthub\Libs\ServiceQueue
 */
final class QueueItem {

  /**
   * The queue item ID.
   *
   * @var string
   */
  protected string $id;

  /**
   * The entity UUID.
   *
   * @var string
   */
  protected string $entityUuid;

  /**
   * The client UUID.
   *
   * @var string
   */
  protected string $clientUuid;

  /**
   * The queue item state.
   *
   * @var string
   */
  protected string $state;

  /**
   * The queue item payload.
   *
   * @var array
   */
  protected array $payload;

  /**
   * The timestamp when the item becomes visible.
   *
   * @var string
   */
  protected string $visibleAt;

  /**
   * The timestamp when the item was created.
   *
   * @var string
   */
  protected string $createdAt;

  /**
   * The timestamp when the item was updated.
   *
   * @var string
   */
  protected string $updatedAt;

  /**
   * Constructs a QueueItem object.
   *
   * @param string $id
   *   The queue item ID.
   * @param string $entity_uuid
   *   The entity UUID.
   * @param string $client_uuid
   *   The client UUID.
   * @param string $state
   *   The queue item state.
   * @param array $payload
   *   The queue item payload.
   * @param string $visible_at
   *   The timestamp when the item becomes visible.
   * @param string $created_at
   *   The timestamp when the item was created.
   * @param string $updated_at
   *   The timestamp when the item was updated.
   */
  public function __construct(string $id, string $entity_uuid, string $client_uuid, string $state, array $payload, string $visible_at, string $created_at, string $updated_at) {
    $this->id = $id;
    $this->entityUuid = $entity_uuid;
    $this->clientUuid = $client_uuid;
    $this->state = $state;
    $this->payload = $payload;
    $this->visibleAt = $visible_at;
    $this->createdAt = $created_at;
    $this->updatedAt = $updated_at;
  }

  /**
   * Creates a QueueItem instance from an array.
   *
   * @param array $queue_item
   *   Array containing queue item data.
   *
   * @return static
   *   A new QueueItem instance.
   *
   * @throws \InvalidArgumentException
   *   When required fields are missing.
   */
  public static function fromArray(array $queue_item): QueueItem {
    $required_fields = ['id', 'entity_uuid', 'client_uuid'];
    foreach ($required_fields as $field) {
      if (empty($queue_item[$field])) {
        throw new \InvalidArgumentException(sprintf('Required field "%s" is missing or empty in queue item data.', $field));
      }
    }

    return new QueueItem(
      $queue_item['id'],
      $queue_item['entity_uuid'],
      $queue_item['client_uuid'],
      $queue_item['state'] ?? '',
      $queue_item['payload'] ?? [],
      $queue_item['visible_at'] ?? '',
      $queue_item['created_at'] ?? '',
      $queue_item['updated_at'] ?? ''
    );
  }

  /**
   * Gets the queue item ID.
   *
   * @return string
   *   The queue item ID.
   */
  public function getId(): string {
    return $this->id;
  }

  /**
   * Gets the entity UUID.
   *
   * @return string
   *   The entity UUID.
   */
  public function getEntityUuid(): string {
    return $this->entityUuid;
  }

  /**
   * Returns the client UUID of the queue item's owner.
   *
   * @return string
   *   The owner's client UUID.
   */
  public function getOwnerUuid(): string {
    return $this->clientUuid;
  }

  /**
   * Gets the queue item state.
   *
   * @return string
   *   The queue item state.
   */
  public function getState(): string {
    return $this->state;
  }

  /**
   * Gets the queue item payload.
   *
   * @return array
   *   The queue item payload.
   */
  public function getPayload(): array {
    return $this->payload;
  }

  /**
   * Gets the action from the payload.
   *
   * @return string
   *   The action string, or 'unknown' if not set.
   */
  public function getAction(): string {
    return $this->payload['action'] ?? 'unknown';
  }

  /**
   * Gets the reason from the payload.
   *
   * @return string
   *   The reason of the item getting into the service queue.
   */
  public function getReason(): string {
    return $this->payload['reason'] ?? '';
  }

  /**
   * Gets the CDF type from the payload.
   *
   * @return string
   *   The CDF type string, or empty string if not set.
   */
  public function getCdfType(): string {
    return $this->payload['type'] ?? '';
  }

  /**
   * Returns the UUID of the CDF's owner.
   *
   * @return string
   *   The client UUID of the origin publisher.
   */
  public function getInitiator(): string {
    return $this->payload['initiator'] ?? '';
  }

  /**
   * Gets the visible at timestamp.
   *
   * @return string
   *   The visible at timestamp.
   */
  public function getVisibleAt(): string {
    return $this->visibleAt;
  }

  /**
   * Gets the created at timestamp.
   *
   * @return string
   *   The created at timestamp.
   */
  public function getCreatedAt(): string {
    return $this->createdAt;
  }

  /**
   * Gets the updated at timestamp.
   *
   * @return string
   *   The updated at timestamp.
   */
  public function getUpdatedAt(): string {
    return $this->updatedAt;
  }

  /**
   * Checks if the queue item action matches one of the given actions.
   *
   * @param array $actions
   *   Array of action strings to check against.
   *
   * @return bool
   *   TRUE if the queue item action matches one of the given actions.
   */
  public function isActionOneOf(array $actions): bool {
    $action = $this->getAction();
    return $action !== 'unknown' && in_array($action, $actions, TRUE);
  }

  /**
   * Checks if the queue item is a specific action.
   *
   * @param string $action
   *   The action to check for.
   *
   * @return bool
   *   TRUE if the queue item is the specified action.
   */
  public function isAction(string $action): bool {
    return $this->getAction() === $action;
  }

  /**
   * Converts the QueueItem back to an array format.
   *
   * @return array
   *   Array representation of the queue item.
   */
  public function toArray(): array {
    return [
      'id' => $this->id,
      'entity_uuid' => $this->entityUuid,
      'client_uuid' => $this->clientUuid,
      'state' => $this->state,
      'payload' => $this->payload,
      'visible_at' => $this->visibleAt,
      'created_at' => $this->createdAt,
      'updated_at' => $this->updatedAt,
    ];
  }

  /**
   * Returns the string representation of the class.
   *
   * @return string
   *   Json encoded format of the class.
   */
  public function __toString(): string {
    return Json::encode($this->toArray());
  }

}
