<?php

declare(strict_types=1);

namespace Drupal\flowdrop_session\EventSubscriber;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\flowdrop\Utility\Duration;
use Drupal\flowdrop_job\Constants\JobStatus;
use Drupal\flowdrop_session\Constants\MessageAnnotation;
use Drupal\flowdrop_session\Entity\FlowDropSessionInterface;
use Drupal\flowdrop_session\Service\SessionServiceInterface;
use Drupal\flowdrop_runtime\Event\JobCompletedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Writes a session log message for each job as it finishes executing.
 *
 * This gives the playground logs panel per-node feedback during a workflow
 * run rather than all logs appearing in a single batch after orchestration.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class JobLogSubscriber implements EventSubscriberInterface {

  public function __construct(
    private readonly EntityTypeManagerInterface $entityTypeManager,
    private readonly SessionServiceInterface $sessionService,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
      JobCompletedEvent::NAME => 'onJobCompleted',
    ];
  }

  /**
   * Writes a log message to the session when a job finishes.
   */
  public function onJobCompleted(JobCompletedEvent $event): void {
    $playgroundContext = $event->getPlaygroundContext();
    if ($playgroundContext === NULL) {
      return;
    }

    /** @var \Drupal\flowdrop_session\Entity\FlowDropSessionInterface|null $session */
    $session = $this->entityTypeManager
      ->getStorage('flowdrop_session')
      ->load($playgroundContext->getSessionId());

    if (!$session instanceof FlowDropSessionInterface) {
      return;
    }

    $job = $event->getJob();
    $status = $job->getStatus();
    $nodeLabel = $job->label() ?: $job->getNodeId();
    $metadata = ['nodeLabel' => $nodeLabel];

    $hierarchy = $playgroundContext->getHierarchy();
    if ($hierarchy !== []) {
      $metadata[MessageAnnotation::METADATA_KEY_HIERARCHY] = $hierarchy;
    }

    // Log content is written to the session panel (not watchdog) and is
    // intentionally plain English; it is not passed through t() because it
    // contains runtime-specific values (durations, error messages) that are
    // not translatable strings. The node label is omitted from the body
    // because the playground renders `nodeLabel` as a separate chip in the
    // log row meta — repeating it in the body produced "Foo / Foo completed
    // in 2ms" rows once the 1.13.0 frontend landed.
    if ($status === JobStatus::FAILED) {
      $errorMessage = $job->getErrorMessage();
      $content = $errorMessage !== '' ? "failed: {$errorMessage}" : 'failed';
      $level = 'error';
    }
    else {
      $execUs = $job->getMetadataValue('execution_time_us');
      if ($execUs !== NULL && $execUs > 0) {
        $duration = Duration::formatMicroseconds((int) $execUs);
        $content = "completed in {$duration}";
      }
      else {
        $content = 'completed';
      }
      $level = 'info';
    }

    $this->sessionService->addLogMessage(
      $session,
      $content,
      $job->getNodeId(),
      $level,
      $metadata,
      $event->getExecutionId() ?: NULL,
    );
  }

}
