<?php

declare(strict_types=1);

namespace Drupal\flowdrop_stategraph\Form;

use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\flowdrop_orchestration\DTO\Orchestrator\OrchestrationRequest;
use Drupal\flowdrop_pipeline\Constants\PipelineStatus;
use Drupal\flowdrop_stategraph\Service\StateGraphOrchestrator;
use Drupal\flowdrop_workflow\WorkflowDefinitionInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Test form for manually testing the StateGraph orchestrator.
 *
 * This form provides an end-user interface to:
 * - Select a workflow to execute
 * - Configure StateGraph options (checkpointer type, max iterations, etc.)
 * - Execute with StateGraph orchestrator
 * - View detailed execution results.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class StateGraphTestForm extends FormBase {

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

  /**
   * The StateGraph orchestrator service.
   *
   * @var \Drupal\flowdrop_stategraph\Service\StateGraphOrchestrator
   */
  protected StateGraphOrchestrator $orchestrator;

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

  /**
   * The messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected MessengerInterface $messengerService;

  /**
   * Constructs a new StateGraphTestForm.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\flowdrop_stategraph\Service\StateGraphOrchestrator $orchestrator
   *   The StateGraph orchestrator service.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   */
  public function __construct(
    EntityTypeManagerInterface $entityTypeManager,
    StateGraphOrchestrator $orchestrator,
    LoggerInterface $logger,
    MessengerInterface $messenger,
  ) {
    $this->entityTypeManager = $entityTypeManager;
    $this->orchestrator = $orchestrator;
    $this->logger = $logger;
    $this->messengerService = $messenger;
  }

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

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return "flowdrop_stategraph_test_form";
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    // Form description.
    $form["description"] = [
      "#type" => "markup",
      "#markup" => "<div class=\"messages messages--info\"><p>" .
      $this->t("Use this form to manually test the StateGraph orchestrator with a selected workflow. This is useful for debugging state management, checkpointing, and conditional routing features.") .
      "</p></div>",
    ];

    // Workflow selection.
    $form["workflow_section"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Workflow Selection"),
    ];

    $workflowOptions = $this->buildWorkflowOptions();

    if (empty($workflowOptions)) {
      $form["workflow_section"]["no_workflows"] = [
        "#type" => "markup",
        "#markup" => "<p><em>" . $this->t("No workflows available. Please create a workflow first.") . "</em></p>",
      ];
      return $form;
    }

    $form["workflow_section"]["workflow_id"] = [
      "#type" => "select",
      "#title" => $this->t("Workflow"),
      "#description" => $this->t("Select the workflow to execute with StateGraph orchestrator."),
      "#options" => $workflowOptions,
      "#empty_option" => $this->t("- Select a workflow -"),
      "#required" => TRUE,
    ];

    // StateGraph configuration.
    $form["stategraph_config"] = [
      "#type" => "fieldset",
      "#title" => $this->t("StateGraph Configuration"),
    ];

    $form["stategraph_config"]["checkpointer_type"] = [
      "#type" => "radios",
      "#title" => $this->t("Checkpointer Type"),
      "#description" => $this->t("Choose where to store state checkpoints."),
      "#options" => [
        "memory" => $this->t("Memory (in-memory, lost after request - good for testing)"),
        "entity" => $this->t("Entity (persistent Drupal storage - production)"),
      ],
      "#default_value" => "memory",
      "#required" => TRUE,
    ];

    $form["stategraph_config"]["max_iterations"] = [
      "#type" => "number",
      "#title" => $this->t("Max Iterations"),
      "#description" => $this->t("Maximum number of loop iterations before stopping (prevents infinite loops)."),
      "#default_value" => 10,
      "#min" => 1,
      "#max" => 1000,
      "#required" => TRUE,
    ];

    $form["stategraph_config"]["create_checkpoints"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Create checkpoints during execution"),
      "#description" => $this->t("Enable to save state snapshots after each node execution."),
      "#default_value" => TRUE,
    ];

    $form["stategraph_config"]["debug_mode"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Debug mode (verbose logging)"),
      "#description" => $this->t("Enable for detailed logging of state changes and execution flow."),
      "#default_value" => TRUE,
    ];

    // Thread configuration.
    $form["thread_config"] = [
      "#type" => "details",
      "#title" => $this->t("Thread / Resume Configuration"),
      "#open" => FALSE,
    ];

    $form["thread_config"]["thread_id"] = [
      "#type" => "textfield",
      "#title" => $this->t("Thread ID"),
      "#description" => $this->t("Optional: Provide a thread ID to continue an existing conversation/session. Leave empty to create a new thread."),
      "#default_value" => "",
    ];

    $form["thread_config"]["resume_checkpoint"] = [
      "#type" => "textfield",
      "#title" => $this->t("Resume from Checkpoint ID"),
      "#description" => $this->t("Optional: Provide a checkpoint ID to resume execution from a specific state."),
      "#default_value" => "",
    ];

    // Initial data.
    $form["initial_data_section"] = [
      "#type" => "details",
      "#title" => $this->t("Initial Data (JSON)"),
      "#open" => FALSE,
    ];

    $form["initial_data_section"]["initial_data"] = [
      "#type" => "textarea",
      "#title" => $this->t("Initial Data"),
      "#description" => $this->t("Provide initial data as JSON. This will be passed to the workflow."),
      "#default_value" => "{\n  \"test_input\": \"Hello StateGraph!\"\n}",
      "#rows" => 5,
    ];

    // Submit button.
    $form["actions"] = [
      "#type" => "actions",
    ];

    $form["actions"]["submit"] = [
      "#type" => "submit",
      "#value" => $this->t("Execute with StateGraph"),
      "#button_type" => "primary",
    ];

    // Results area (populated after submission).
    if ($form_state->get("execution_results") !== NULL) {
      $form["results"] = $this->buildResultsSection($form_state);
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    // Validate JSON.
    $initialData = $form_state->getValue("initial_data");
    if (!empty($initialData)) {
      $decoded = json_decode($initialData, TRUE);
      if (json_last_error() !== JSON_ERROR_NONE) {
        $form_state->setErrorByName("initial_data", $this->t("Invalid JSON: @error", [
          "@error" => json_last_error_msg(),
        ]));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $workflowId = $form_state->getValue("workflow_id");
    $checkpointerType = $form_state->getValue("checkpointer_type");
    $maxIterations = (int) $form_state->getValue("max_iterations");
    $createCheckpoints = (bool) $form_state->getValue("create_checkpoints");
    $debugMode = (bool) $form_state->getValue("debug_mode");
    $threadId = $form_state->getValue("thread_id") ?: NULL;
    $resumeCheckpoint = $form_state->getValue("resume_checkpoint") ?: NULL;
    $initialDataJson = $form_state->getValue("initial_data");

    // Parse initial data.
    $initialData = [];
    if (!empty($initialDataJson)) {
      $decoded = json_decode($initialDataJson, TRUE);
      if (is_array($decoded)) {
        $initialData = $decoded;
      }
    }

    try {
      // Load the workflow.
      $workflow = $this->entityTypeManager
        ->getStorage("flowdrop_workflow")
        ->load($workflowId);

      if (!$workflow instanceof WorkflowDefinitionInterface) {
        throw new \RuntimeException("Workflow not found: {$workflowId}");
      }

      // Build workflow data array.
      $workflowData = [
        "id" => $workflow->id(),
        "label" => $workflow->getLabel(),
        "description" => $workflow->getDescription(),
        "nodes" => $workflow->getNodes(),
        "edges" => $workflow->getEdges(),
        "metadata" => $workflow->getMetadata(),
      ];

      // Create orchestration request with StateGraph options.
      $request = new OrchestrationRequest(
        workflowId: (string) $workflow->id(),
        pipelineId: "stategraph_test_" . time(),
        workflow: $workflowData,
        initialData: $initialData,
        options: [
          "stategraph" => [
            "checkpointerType" => $checkpointerType,
            "maxIterations" => $maxIterations,
            "createCheckpoints" => $createCheckpoints,
            "debugMode" => $debugMode,
            "threadId" => $threadId,
            "resumeFromCheckpoint" => $resumeCheckpoint,
          ],
        ],
      );

      $this->logger->info("Starting StateGraph test execution for workflow @id", [
        "@id" => $workflowId,
      ]);

      // Execute with StateGraph orchestrator.
      $startTime = microtime(TRUE);
      $response = $this->orchestrator->orchestrate($request);
      $totalTime = microtime(TRUE) - $startTime;

      // Store results for display.
      $form_state->set("execution_results", [
        "success" => TRUE,
        "execution_id" => $response->getExecutionId(),
        "status" => $response->getStatus(),
        "execution_time" => $response->getExecutionTime(),
        "total_time" => $totalTime,
        "results" => $response->getResults(),
        "metadata" => $response->getMetadata(),
      ]);

      $this->messengerService->addStatus($this->t("StateGraph execution completed with status: @status", [
        "@status" => $response->getStatus(),
      ]));

      // Log success.
      $this->logger->info("StateGraph test execution completed: @status in @time seconds", [
        "@status" => $response->getStatus(),
        "@time" => round($totalTime, 3),
      ]);

    }
    catch (\Exception $e) {
      $form_state->set("execution_results", [
        "success" => FALSE,
        "error" => $e->getMessage(),
        "trace" => $e->getTraceAsString(),
      ]);

      $this->messengerService->addError($this->t("StateGraph execution failed: @message", [
        "@message" => $e->getMessage(),
      ]));

      $this->logger->error("StateGraph test execution failed: @message", [
        "@message" => $e->getMessage(),
      ]);
    }

    // Rebuild form to show results.
    $form_state->setRebuild(TRUE);
  }

  /**
   * Builds the workflow options array.
   *
   * @return array<string, string>
   *   Array of workflow options keyed by ID.
   */
  protected function buildWorkflowOptions(): array {
    $options = [];

    try {
      $workflows = $this->entityTypeManager
        ->getStorage("flowdrop_workflow")
        ->loadMultiple();

      foreach ($workflows as $workflow) {
        if ($workflow instanceof WorkflowDefinitionInterface) {
          $id = $workflow->id();
          if (is_string($id)) {
            $nodes = $workflow->getNodes();
            $edges = $workflow->getEdges();
            $options[$id] = sprintf(
              "%s (%d nodes, %d edges)",
              $workflow->label(),
              count($nodes),
              count($edges)
            );
          }
        }
      }
    }
    catch (\Exception $e) {
      $this->logger->error("Failed to load workflows: @message", [
        "@message" => $e->getMessage(),
      ]);
    }

    return $options;
  }

  /**
   * Builds the results section for display after execution.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return array<string, mixed>
   *   Form element array for results.
   */
  protected function buildResultsSection(FormStateInterface $form_state): array {
    $results = $form_state->get("execution_results");

    $section = [
      "#type" => "fieldset",
      "#title" => $this->t("Execution Results"),
      "#attributes" => [
        "class" => ["stategraph-results"],
      ],
    ];

    if ($results["success"]) {
      // Success display.
      $section["status"] = [
        "#type" => "item",
        "#title" => $this->t("Status"),
        "#markup" => "<strong style=\"color: " . ($results["status"] === PipelineStatus::COMPLETED ? "green" : "orange") . "\">" . Html::escape($results["status"]) . "</strong>",
      ];

      $section["execution_id"] = [
        "#type" => "item",
        "#title" => $this->t("Execution ID"),
        "#markup" => "<code>" . Html::escape($results["execution_id"]) . "</code>",
      ];

      $section["timing"] = [
        "#type" => "item",
        "#title" => $this->t("Execution Time"),
        "#markup" => round($results["execution_time"], 3) . " seconds (total: " . round($results["total_time"], 3) . "s)",
      ];

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

      $section["metadata"]["content"] = [
        "#type" => "markup",
        "#markup" => "<pre>" . htmlspecialchars(json_encode($results["metadata"], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . "</pre>",
      ];

      // Results.
      $section["output"] = [
        "#type" => "details",
        "#title" => $this->t("Node Results"),
        "#open" => FALSE,
      ];

      $section["output"]["content"] = [
        "#type" => "markup",
        "#markup" => "<pre>" . htmlspecialchars(json_encode($results["results"], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . "</pre>",
      ];

      // Final state (if available).
      if (isset($results["metadata"]["final_state"])) {
        $section["final_state"] = [
          "#type" => "details",
          "#title" => $this->t("Final State"),
          "#open" => TRUE,
        ];

        $section["final_state"]["content"] = [
          "#type" => "markup",
          "#markup" => "<pre>" . htmlspecialchars(json_encode($results["metadata"]["final_state"], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . "</pre>",
        ];
      }

    }
    else {
      // Error display.
      $section["error"] = [
        "#type" => "item",
        "#title" => $this->t("Error"),
        "#markup" => "<strong style=\"color: red\">" . htmlspecialchars($results["error"]) . "</strong>",
      ];

      $section["trace"] = [
        "#type" => "details",
        "#title" => $this->t("Stack Trace"),
        "#open" => FALSE,
      ];

      $section["trace"]["content"] = [
        "#type" => "markup",
        "#markup" => "<pre style=\"font-size: 11px; max-height: 300px; overflow: auto;\">" . htmlspecialchars($results["trace"]) . "</pre>",
      ];
    }

    return $section;
  }

}
