<?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_job\Constants\JobStatus;
use Drupal\flowdrop_runtime\Service\Monitoring\ExecutionMonitor;
use Drupal\flowdrop_runtime\Service\RealTime\RealTimeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
 * REST API controller for real-time status endpoints.
 *
 * These endpoints are gated by the "access flowdrop runtime api" permission
 * with NO per-execution ownership check: any holder may present any execution
 * id. This is safe ONLY because RealTimeManager reads request-scoped, in-memory
 * StatusTracker state — a polling request sees an empty tracker for executions
 * it did not populate this request, so foreign ids return 404, not data.
 *
 * If StatusTracker ever gains persistent backing (state, cache, a long-running
 * app server), this invariant breaks and these endpoints WILL leak cross-user
 * execution metadata. At that point add an ownership check against the owning
 * pipeline here, as SnapshotApiController does with $entity->access('view').
 * RuntimeStatusApiAccessTest pins this contract.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class StatusController extends ControllerBase {

  use ApiResponseTrait;

  public function __construct(
    private readonly RealTimeManagerInterface $realTimeManager,
    private readonly ExecutionMonitor $executionMonitor,
  ) {}

  /**
   * Create controller instance.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The service container.
   *
   * @return static
   *   The controller instance.
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('flowdrop_runtime.real_time_manager'),
      $container->get('flowdrop_runtime.execution_monitor')
    );
  }

  /**
   * Get execution status for polling.
   *
   * @param string $executionId
   *   The execution ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with execution status.
   */
  public function getExecutionStatus(string $executionId): JsonResponse {
    try {
      $status = $this->realTimeManager->getExecutionStatus($executionId);

      if (empty($status)) {
        return $this->errorResponse('Execution not found', 404);
      }

      return $this->successResponse([
        'execution_id' => $executionId,
        'status' => $status,
      ]);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Error fetching execution status: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to fetch execution status', 500);
    }
  }

  /**
   * Get node statuses for an execution.
   *
   * @param string $executionId
   *   The execution ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with node statuses.
   */
  public function getNodeStatuses(string $executionId): JsonResponse {
    try {
      $nodeStatuses = $this->realTimeManager->getNodeStatuses($executionId);

      return $this->successResponse([
        'execution_id' => $executionId,
        'node_statuses' => $nodeStatuses,
      ]);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Error fetching node statuses: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to fetch node statuses', 500);
    }
  }

  /**
   * Get detailed execution information.
   *
   * @param string $executionId
   *   The execution ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with detailed execution info.
   */
  public function getExecutionDetails(string $executionId): JsonResponse {
    try {
      $executionStatus = $this->realTimeManager->getExecutionStatus($executionId);
      $nodeStatuses = $this->realTimeManager->getNodeStatuses($executionId);

      if (empty($executionStatus)) {
        return $this->errorResponse('Execution not found', 404);
      }

      // Calculate metrics.
      $totalNodes = count($nodeStatuses);
      $completedNodes = 0;
      $failedNodes = 0;
      $totalExecutionTime = 0;

      foreach ($nodeStatuses as $nodeStatus) {
        if ($nodeStatus['status'] === JobStatus::COMPLETED) {
          $completedNodes++;
          $totalExecutionTime += $nodeStatus['execution_time'] ?? 0;
        }
        elseif ($nodeStatus['status'] === JobStatus::FAILED) {
          $failedNodes++;
        }
      }

      return $this->successResponse([
        'execution_id' => $executionId,
        'execution_status' => $executionStatus,
        'node_statuses' => $nodeStatuses,
        'metrics' => [
          'total_nodes' => $totalNodes,
          'completed_nodes' => $completedNodes,
          'failed_nodes' => $failedNodes,
          'pending_nodes' => $totalNodes - $completedNodes - $failedNodes,
          'total_execution_time' => $totalExecutionTime,
        ],
        'timestamp' => date('c'),
      ]);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Error fetching execution details: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to fetch execution details', 500);
    }
  }

  /**
   * Get system health status.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with system health information.
   */
  public function getHealth(): JsonResponse {
    try {
      $healthStatus = [
        'status' => 'healthy',
        'timestamp' => date('c'),
        'version' => '1.0.0',
        'services' => [
          'real_time_manager' => 'operational',
          'execution_monitor' => 'operational',
          'data_flow_manager' => 'operational',
          'error_handler' => 'operational',
        ],
        'system' => [
          'memory_usage' => memory_get_usage(TRUE),
          'memory_limit' => ini_get('memory_limit'),
          'php_version' => phpversion(),
        ],
      ];

      return $this->successResponse($healthStatus);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Error fetching health status: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to fetch health status', 500);
    }
  }

  /**
   * Get system performance metrics.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with system metrics.
   */
  public function getSystemMetrics(): JsonResponse {
    try {
      $metrics = $this->executionMonitor->getPerformanceMetrics();

      return $this->successResponse([
        'metrics' => $metrics,
        'timestamp' => date('c'),
        'period' => 'current',
      ]);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_runtime')->error('Error fetching system metrics: @message', [
        '@message' => $e->getMessage(),
      ]);
      return $this->errorResponse('Failed to fetch system metrics', 500);
    }
  }

}
