<?php

declare(strict_types=1);

namespace Drupal\flowdrop_stategraph\Controller;

use Drupal\Component\Utility\Html;
use Drupal\Core\Url;
use Drupal\Core\Controller\ControllerBase;
use Drupal\flowdrop_stategraph\Entity\FlowDropStateCheckpointInterface;
use Drupal\flowdrop_stategraph\Service\CheckpointerFactory;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Controller for viewing and managing StateGraph checkpoints.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class CheckpointController extends ControllerBase {

  /**
   * The checkpointer factory.
   *
   * @var \Drupal\flowdrop_stategraph\Service\CheckpointerFactory
   */
  protected CheckpointerFactory $checkpointerFactory;

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected LoggerInterface $logger;

  /**
   * Constructs a CheckpointController.
   *
   * @param \Drupal\flowdrop_stategraph\Service\CheckpointerFactory $checkpointerFactory
   *   The checkpointer factory.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   */
  public function __construct(
    CheckpointerFactory $checkpointerFactory,
    LoggerInterface $logger,
  ) {
    $this->checkpointerFactory = $checkpointerFactory;
    $this->logger = $logger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get("flowdrop_stategraph.checkpointer_factory"),
      $container->get("logger.channel.flowdrop_stategraph"),
    );
  }

  /**
   * Lists all stored checkpoints.
   *
   * @return array<string, mixed>
   *   A render array.
   */
  public function listCheckpoints(): array {
    $build = [];

    $build["description"] = [
      "#type" => "markup",
      "#markup" => "<p>" . $this->t("View stored StateGraph checkpoints. Checkpoints are snapshots of workflow state saved during execution.") . "</p>",
    ];

    // Try to load entity checkpoints.
    try {
      $storage = $this->entityTypeManager()->getStorage("state_checkpoint");
      $checkpoints = $storage->loadMultiple();

      if (empty($checkpoints)) {
        $build["empty"] = [
          "#type" => "markup",
          "#markup" => "<div class=\"messages messages--warning\"><p>" .
          $this->t("No checkpoints found. Run a workflow with the StateGraph orchestrator (using Entity checkpointer) to create checkpoints.") .
          "</p></div>",
        ];

        // Show memory checkpointer note.
        $build["memory_note"] = [
          "#type" => "markup",
          "#markup" => "<p><em>" . $this->t("Note: Memory checkpoints are not persisted and are only available during the request. Use 'Entity' checkpointer type for persistent checkpoints.") . "</em></p>",
        ];

        return $build;
      }

      // Build table.
      $build["table"] = [
        "#type" => "table",
        "#header" => [
          $this->t("ID"),
          $this->t("Thread ID"),
          $this->t("Node ID"),
          $this->t("Created"),
          $this->t("Operations"),
        ],
        "#rows" => [],
        "#empty" => $this->t("No checkpoints found."),
      ];

      foreach ($checkpoints as $checkpoint) {
        if ($checkpoint instanceof FlowDropStateCheckpointInterface) {
          $build["table"]["#rows"][] = [
            $checkpoint->id(),
            $checkpoint->getThreadId(),
            $checkpoint->getNodeId(),
            date("Y-m-d H:i:s", $checkpoint->getCreatedTime()),
            [
              "data" => [
                "#type" => "link",
                "#title" => $this->t("View"),
                "#url" => Url::fromRoute("flowdrop_stategraph.checkpoint_view", [
                  "checkpoint_id" => $checkpoint->id(),
                ]),
              ],
            ],
          ];
        }
      }

    }
    catch (\Exception $e) {
      // Entity type might not exist yet.
      $build["error"] = [
        "#type" => "inline_template",
        "#template" => '<div class="messages messages--warning"><p>{{ message }}</p><p><code>{{ error }}</code></p></div>',
        "#context" => [
          "message" => $this->t("FlowDropStateCheckpoint entity is not available. The entity may not be installed yet. Run database updates or reinstall the module."),
          "error" => $e->getMessage(),
        ],
      ];
    }

    return $build;
  }

  /**
   * Views a single checkpoint.
   *
   * @param string $checkpoint_id
   *   The checkpoint ID.
   *
   * @return array<string, mixed>
   *   A render array.
   */
  public function viewCheckpoint(string $checkpoint_id): array {
    $build = [];

    try {
      $storage = $this->entityTypeManager()->getStorage("state_checkpoint");
      $checkpoint = $storage->load($checkpoint_id);

      if ($checkpoint === NULL || !$checkpoint instanceof FlowDropStateCheckpointInterface) {
        $build["not_found"] = [
          "#type" => "markup",
          "#markup" => "<div class=\"messages messages--error\"><p>" .
          $this->t("Checkpoint @id not found.", ["@id" => $checkpoint_id]) .
          "</p></div>",
        ];
        return $build;
      }

      // Checkpoint details.
      $build["details"] = [
        "#type" => "fieldset",
        "#title" => $this->t("Checkpoint Details"),
      ];

      $build["details"]["id"] = [
        "#type" => "item",
        "#title" => $this->t("Checkpoint ID"),
        "#markup" => "<code>" . Html::escape($checkpoint->id()) . "</code>",
      ];

      $build["details"]["thread_id"] = [
        "#type" => "item",
        "#title" => $this->t("Thread ID"),
        "#markup" => "<code>" . Html::escape($checkpoint->getThreadId()) . "</code>",
      ];

      $build["details"]["node_id"] = [
        "#type" => "item",
        "#title" => $this->t("Node ID"),
        "#markup" => Html::escape($checkpoint->getNodeId()),
      ];

      $build["details"]["created"] = [
        "#type" => "item",
        "#title" => $this->t("Created"),
        "#markup" => date("Y-m-d H:i:s", $checkpoint->getCreatedTime()),
      ];

      // State data.
      $build["state"] = [
        "#type" => "details",
        "#title" => $this->t("State Data"),
        "#open" => TRUE,
      ];

      $stateData = $checkpoint->getStateData();
      $build["state"]["content"] = [
        "#type" => "markup",
        "#markup" => "<pre>" . htmlspecialchars(json_encode($stateData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) ?: "{}") . "</pre>",
      ];

      // Metadata.
      $build["metadata"] = [
        "#type" => "details",
        "#title" => $this->t("Metadata"),
        "#open" => FALSE,
      ];

      $metadata = $checkpoint->getMetadata();
      $build["metadata"]["content"] = [
        "#type" => "markup",
        "#markup" => "<pre>" . htmlspecialchars(json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) ?: "{}") . "</pre>",
      ];

      // Back link.
      $build["back"] = [
        "#type" => "link",
        "#title" => $this->t("« Back to Checkpoints"),
        "#url" => Url::fromRoute("flowdrop_stategraph.checkpoints"),
        "#attributes" => ["class" => ["button"]],
      ];

    }
    catch (\Exception $e) {
      $build["error"] = [
        "#type" => "markup",
        "#markup" => "<div class=\"messages messages--error\"><p>" .
        $this->t("Error loading checkpoint: @message", ["@message" => $e->getMessage()]) .
        "</p></div>",
      ];
    }

    return $build;
  }

}
