<?php

declare(strict_types=1);

namespace Drupal\eb\Result;

/**
 * Value object representing preview results.
 */
final class PreviewResult implements \JsonSerializable {

  /**
   * Constructor.
   *
   * @param string $description
   *   Human-readable description of changes.
   * @param array<int, array<string, mixed>> $createdEntities
   *   Entities that will be created.
   * @param array<int, array<string, mixed>> $modifiedEntities
   *   Entities that will be modified.
   * @param array<int, array<string, mixed>> $deletedEntities
   *   Entities that will be deleted.
   * @param array<int, string> $warnings
   *   Warnings about potential issues.
   */
  public function __construct(
    protected string $description = '',
    protected array $createdEntities = [],
    protected array $modifiedEntities = [],
    protected array $deletedEntities = [],
    protected array $warnings = [],
  ) {}

  /**
   * Gets the description of changes.
   */
  public function getDescription(): string {
    return $this->description;
  }

  /**
   * Gets entities that will be created.
   *
   * @return array<int, array<string, mixed>>
   *   Array of entity information.
   */
  public function getCreatedEntities(): array {
    return $this->createdEntities;
  }

  /**
   * Gets entities that will be modified.
   *
   * @return array<int, array<string, mixed>>
   *   Array of entity information with before/after states.
   */
  public function getModifiedEntities(): array {
    return $this->modifiedEntities;
  }

  /**
   * Gets entities that will be deleted.
   *
   * @return array<int, array<string, mixed>>
   *   Array of entity information.
   */
  public function getDeletedEntities(): array {
    return $this->deletedEntities;
  }

  /**
   * Gets warnings.
   *
   * @return array<int, string>
   *   Array of warning messages.
   */
  public function getWarnings(): array {
    return $this->warnings;
  }

  /**
   * Checks if there are any warnings.
   */
  public function hasWarnings(): bool {
    return !empty($this->warnings);
  }

  /**
   * Adds an entity that will be created.
   *
   * @param array<string, mixed> $entityInfo
   *   Entity information.
   */
  public function addCreatedEntity(array $entityInfo): void {
    $this->createdEntities[] = $entityInfo;
  }

  /**
   * Adds an entity that will be modified.
   *
   * @param array<string, mixed> $entityInfo
   *   Entity information with before/after states.
   */
  public function addModifiedEntity(array $entityInfo): void {
    $this->modifiedEntities[] = $entityInfo;
  }

  /**
   * Adds an entity that will be deleted.
   *
   * @param array<string, mixed> $entityInfo
   *   Entity information.
   */
  public function addDeletedEntity(array $entityInfo): void {
    $this->deletedEntities[] = $entityInfo;
  }

  /**
   * Adds a warning.
   *
   * @param string $warning
   *   Warning message.
   */
  public function addWarning(string $warning): void {
    $this->warnings[] = $warning;
  }

  /**
   * Adds an operation to the preview.
   *
   * @param string $operationType
   *   The operation type (create, update, delete).
   * @param string $entityType
   *   The entity type.
   * @param string $entityId
   *   The entity ID.
   * @param string $description
   *   Description of the operation.
   */
  public function addOperation(string $operationType, string $entityType, string $entityId, string $description): void {
    $entity_info = [
      'operation' => $operationType,
      'entity_type' => $entityType,
      'entity_id' => $entityId,
      'description' => $description,
    ];

    match ($operationType) {
      'create' => $this->addCreatedEntity($entity_info),
      'update' => $this->addModifiedEntity($entity_info),
      'delete' => $this->addDeletedEntity($entity_info),
      default => NULL,
    };
  }

  /**
   * Adds details to the description.
   *
   * @param array<string, mixed> $details
   *   Details to add.
   */
  public function addDetails(array $details): void {
    $details_text = [];
    foreach ($details as $key => $value) {
      // Handle array values by converting to JSON or extracting type.
      if (is_array($value)) {
        $value = $value['type'] ?? json_encode($value);
      }
      $details_text[] = "$key: $value";
    }
    $this->description .= "\n" . implode("\n", $details_text);
  }

  /**
   * Gets the operation type.
   *
   * @return string
   *   The operation type.
   */
  public function getOperationType(): string {
    // Derive from created/modified/deleted entities.
    if (!empty($this->createdEntities)) {
      return 'create';
    }
    if (!empty($this->modifiedEntities)) {
      return 'update';
    }
    if (!empty($this->deletedEntities)) {
      return 'delete';
    }
    return 'unknown';
  }

  /**
   * Gets a summary of the preview.
   *
   * @return string
   *   Summary text.
   */
  public function getSummary(): string {
    return $this->description;
  }

  /**
   * Gets detailed preview information.
   *
   * @return array<string, mixed>
   *   Detailed information.
   */
  public function getDetails(): array {
    return [
      'created' => $this->createdEntities,
      'modified' => $this->modifiedEntities,
      'deleted' => $this->deletedEntities,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function jsonSerialize(): array {
    return [
      'type' => $this->getOperationType(),
      'summary' => $this->getSummary(),
      'details' => $this->getDetails(),
      'warnings' => $this->getWarnings(),
    ];
  }

}
