<?php

declare(strict_types=1);

namespace Drupal\flowdrop_stategraph\Service;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\flowdrop_stategraph\Checkpointer\CheckpointerInterface;
use Drupal\flowdrop_stategraph\Checkpointer\EntityCheckpointer;
use Drupal\flowdrop_stategraph\Checkpointer\MemoryCheckpointer;
use Psr\Log\LoggerInterface;

/**
 * Factory for creating checkpointer instances.
 *
 * This factory creates the appropriate checkpointer based on configuration:
 * - "memory": In-memory storage for development/testing.
 * - "entity": Drupal entity storage for production.
 *
 * The checkpointer type is configured at the workflow/pipeline level.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class CheckpointerFactory {

  /**
   * Cached checkpointer instances.
   *
   * @var array<string, \Drupal\flowdrop_stategraph\Checkpointer\CheckpointerInterface>
   */
  private array $instances = [];

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  private readonly EntityTypeManagerInterface $entityTypeManager;

  /**
   * The logger service.
   *
   * @var \Psr\Log\LoggerInterface
   */
  private readonly LoggerInterface $logger;

  /**
   * Constructs a new CheckpointerFactory.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   */
  public function __construct(
    EntityTypeManagerInterface $entityTypeManager,
    LoggerInterface $logger,
  ) {
    $this->entityTypeManager = $entityTypeManager;
    $this->logger = $logger;
  }

  /**
   * Creates a checkpointer instance based on type.
   *
   * @param string $type
   *   The checkpointer type ("memory" or "entity").
   *
   * @return \Drupal\flowdrop_stategraph\Checkpointer\CheckpointerInterface
   *   The checkpointer instance.
   *
   * @throws \InvalidArgumentException
   *   When an unsupported type is requested.
   */
  public function create(string $type): CheckpointerInterface {
    // Return cached instance if available.
    if (isset($this->instances[$type])) {
      return $this->instances[$type];
    }

    $checkpointer = match ($type) {
      "memory" => new MemoryCheckpointer($this->logger),
      "entity" => new EntityCheckpointer($this->entityTypeManager, $this->logger),
      default => throw new \InvalidArgumentException(
        "Unsupported checkpointer type: {$type}. Supported types: memory, entity."
      ),
    };

    // Cache the instance.
    $this->instances[$type] = $checkpointer;

    $this->logger->debug("CheckpointerFactory: created @type checkpointer", [
      "@type" => $type,
    ]);

    return $checkpointer;
  }

  /**
   * Gets a memory checkpointer (convenience method).
   *
   * @return \Drupal\flowdrop_stategraph\Checkpointer\CheckpointerInterface
   *   A memory checkpointer instance.
   */
  public function createMemory(): CheckpointerInterface {
    return $this->create("memory");
  }

  /**
   * Gets an entity checkpointer (convenience method).
   *
   * @return \Drupal\flowdrop_stategraph\Checkpointer\CheckpointerInterface
   *   An entity checkpointer instance.
   */
  public function createEntity(): CheckpointerInterface {
    return $this->create("entity");
  }

}
