<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Controller\Api;

use Drupal\Core\Controller\ControllerBase;
use Drupal\flowdrop\Controller\Api\ApiResponseTrait;
use Drupal\flowdrop_orchestration\DTO\Snapshot\WorkflowSnapshot;
use Drupal\flowdrop_runtime\Service\WorkflowState\EntitySnapshotStorage;
use Drupal\flowdrop_runtime\Service\WorkflowState\WorkflowStateManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * REST API controller for workflow snapshot management.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class SnapshotApiController extends ControllerBase {

  use ApiResponseTrait;

  /**
   * Constructs a new SnapshotApiController.
   *
   * @param \Drupal\flowdrop_runtime\Service\WorkflowState\EntitySnapshotStorage $snapshotStorage
   *   The entity snapshot storage service.
   * @param \Drupal\flowdrop_runtime\Service\WorkflowState\WorkflowStateManagerInterface $stateManager
   *   The workflow state manager service.
   */
  public function __construct(
    private readonly EntitySnapshotStorage $snapshotStorage,
    private readonly WorkflowStateManagerInterface $stateManager,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('flowdrop_runtime.entity_snapshot_storage'),
      $container->get('flowdrop_runtime.workflow_state_manager'),
    );
  }

  /**
   * Gets a workflow snapshot by execution ID.
   *
   * @param string $execution_id
   *   The execution ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  public function get(string $execution_id): JsonResponse {
    // Verify entity-level access before returning data.
    $entity = $this->snapshotStorage->loadByExecutionId($execution_id);
    if ($entity === NULL) {
      return $this->errorResponse('Snapshot not found', Response::HTTP_NOT_FOUND);
    }
    if (!$entity->access('view')) {
      return $this->errorResponse('Access denied', Response::HTTP_FORBIDDEN);
    }

    // First check in-memory cache.
    $snapshot = $this->stateManager->getSnapshot($execution_id);

    // Fall back to persistent storage.
    if ($snapshot === NULL) {
      $snapshot = $this->snapshotStorage->load($execution_id);
    }

    if ($snapshot === NULL) {
      return $this->errorResponse('Snapshot not found', Response::HTTP_NOT_FOUND);
    }

    return $this->successResponse([
      'snapshot' => $snapshot->toArray(),
    ]);
  }

  /**
   * Saves a workflow snapshot.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  public function save(Request $request): JsonResponse {
    $data = $this->decodeJsonRequest($request);

    try {
      $snapshot = WorkflowSnapshot::fromArray($data);
      $entity = $this->snapshotStorage->save($snapshot);

      return $this->successResponse([
        'entity_id' => $entity->id(),
        'execution_id' => $snapshot->executionId,
      ], Response::HTTP_CREATED);
    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Failed to save snapshot: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to save snapshot', Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Deletes a workflow snapshot.
   *
   * @param string $execution_id
   *   The execution ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  public function delete(string $execution_id): JsonResponse {
    // Verify entity-level access before deleting.
    $entity = $this->snapshotStorage->loadByExecutionId($execution_id);
    if ($entity === NULL) {
      return $this->errorResponse('Snapshot not found', Response::HTTP_NOT_FOUND);
    }
    if (!$entity->access('delete')) {
      return $this->errorResponse('Access denied', Response::HTTP_FORBIDDEN);
    }

    // Delete from persistent storage.
    $deleted = $this->snapshotStorage->delete($execution_id);

    // Also delete from in-memory cache.
    $this->stateManager->delete($execution_id);

    if (!$deleted) {
      return $this->errorResponse('Snapshot not found', Response::HTTP_NOT_FOUND);
    }

    return $this->successResponse([
      'message' => 'Snapshot deleted',
      'execution_id' => $execution_id,
    ]);
  }

  /**
   * Lists workflow snapshots with optional filtering.
   *
   * Query parameters:
   * - workflow_id: Filter by workflow ID
   * - thread_id: Filter by thread ID
   * - status: Filter by status
   * - limit: Maximum number of results (default 50)
   * - offset: Offset for pagination (default 0)
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  public function list(Request $request): JsonResponse {
    $workflowId = $request->query->get('workflow_id');
    $threadId = $request->query->get('thread_id');
    $status = $request->query->get('status');
    $limit = min((int) $request->query->get('limit', 50), 100);
    $offset = max((int) $request->query->get('offset', 0), 0);

    $storage = $this->entityTypeManager()->getStorage('flowdrop_workflow_snapshot');
    $query = $storage->getQuery()
      ->accessCheck(TRUE)
      ->sort('created', 'DESC')
      ->range($offset, $limit);

    if ($workflowId !== NULL) {
      $query->condition('workflow_id', $workflowId);
    }

    if ($threadId !== NULL) {
      $query->condition('thread_id', $threadId);
    }

    if ($status !== NULL) {
      $query->condition('snapshot_status', $status);
    }

    $ids = $query->execute();
    $entities = $storage->loadMultiple($ids);

    $snapshots = [];
    foreach ($entities as $entity) {
      /** @var \Drupal\flowdrop_runtime\Entity\FlowDropWorkflowSnapshotInterface $entity */
      $snapshots[] = [
        'entity_id' => $entity->id(),
        'execution_id' => $entity->getExecutionId(),
        'workflow_id' => $entity->getWorkflowId(),
        'status' => $entity->getSnapshotStatus(),
        'thread_id' => $entity->getThreadId(),
        'created' => (int) $entity->get('created')->value,
        'changed' => (int) $entity->getChangedTime(),
        'node_count' => count($entity->getNodeStates()),
      ];
    }

    // Get total count for pagination.
    $countQuery = $storage->getQuery()
      ->accessCheck(TRUE)
      ->count();

    if ($workflowId !== NULL) {
      $countQuery->condition('workflow_id', $workflowId);
    }
    if ($threadId !== NULL) {
      $countQuery->condition('thread_id', $threadId);
    }
    if ($status !== NULL) {
      $countQuery->condition('snapshot_status', $status);
    }

    $total = (int) $countQuery->execute();

    return $this->paginatedResponse($snapshots, $total, $limit, $offset);
  }

}
