<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Plugin\Orchestrator;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_orchestration\Attribute\Orchestrator;
use Drupal\flowdrop_orchestration\DTO\Orchestrator\OrchestrationRequest;
use Drupal\flowdrop_orchestration\DTO\Orchestrator\OrchestrationResponse;
use Drupal\flowdrop_orchestration\Plugin\Orchestrator\OrchestratorPluginBase;
use Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Synchronous pipeline-based workflow orchestrator plugin.
 *
 * This orchestrator executes workflows by creating a pipeline entity,
 * generating jobs, and executing them synchronously with job tracking.
 *
 * This plugin delegates to the SynchronousPipelineOrchestrator service which is
 * configured with all required dependencies including the WorkflowStateManager
 * for snapshot generation.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[Orchestrator(
  id: "synchronous_pipeline",
  label: new TranslatableMarkup("Synchronous Pipeline Orchestrator"),
  description: "Executes workflows synchronously using pipeline entities with job tracking",
  capabilities: [
    "synchronous_execution",
    "retry_support",
    "error_recovery",
    "pipeline_based",
    "job_tracking",
    "interrupt_support",
  ],
)]
class SynchronousPipelineOrchestratorPlugin extends OrchestratorPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The underlying orchestrator service.
   *
   * @var \Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator
   */
  protected SynchronousPipelineOrchestrator $orchestratorService;

  /**
   * Constructs a new SynchronousPipelineOrchestratorPlugin.
   *
   * @param array<string, mixed> $configuration
   *   A configuration array.
   * @param string $plugin_id
   *   The plugin ID.
   * @param mixed $plugin_definition
   *   The plugin definition.
   * @param \Drupal\flowdrop_runtime\Service\Orchestrator\SynchronousPipelineOrchestrator $orchestratorService
   *   The synchronous pipeline orchestrator service (fully configured
   *   with all deps).
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    SynchronousPipelineOrchestrator $orchestratorService,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->orchestratorService = $orchestratorService;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get("flowdrop_runtime.synchronous_pipeline_orchestrator"),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function orchestrate(OrchestrationRequest $request): OrchestrationResponse {
    return $this->orchestratorService->orchestrate($request);
  }

  /**
   * {@inheritdoc}
   */
  public function supportsWorkflow(array $workflow): bool {
    return $this->orchestratorService->supportsWorkflow($workflow);
  }

  /**
   * {@inheritdoc}
   */
  public function getCapabilities(): array {
    return $this->orchestratorService->getCapabilities();
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state, array $settings): array {
    // Merge with defaults to ensure all settings have values.
    $settings = array_merge($this->getDefaultConfiguration(), $settings);

    // Pipeline-specific configuration.
    $form["pipeline"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Pipeline Settings"),
      "#description" => $this->t("Configure how pipelines are created and managed for this trigger."),
    ];

    $form["pipeline"]["pipeline_mode"] = [
      "#type" => "select",
      "#title" => $this->t("Pipeline Mode"),
      "#description" => $this->t("Controls how pipelines are created when this trigger fires."),
      "#options" => [
        "new" => $this->t("New pipeline each time - Create a fresh pipeline for every trigger execution"),
        "reuse" => $this->t("Reuse existing pipeline - Use an existing pipeline if available"),
        "singleton" => $this->t("Singleton - Only one active pipeline at a time for this trigger"),
      ],
      "#default_value" => $settings["pipeline_mode"] ?? "new",
    ];

    $form["pipeline"]["pipeline_id"] = [
      "#type" => "textfield",
      "#title" => $this->t("Pipeline ID"),
      "#description" => $this->t("Specify a pipeline ID for 'reuse' mode. Leave empty for auto-generated ID."),
      "#default_value" => $settings["pipeline_id"] ?? "",
      "#maxlength" => 255,
      "#states" => [
        "visible" => [
          ":input[name=\"orchestrator_settings[pipeline][pipeline_mode]\"]" => ["value" => "reuse"],
        ],
      ],
    ];

    // Job execution settings.
    $form["jobs"] = [
      "#type" => "fieldset",
      "#title" => $this->t("Job Execution Settings"),
      "#description" => $this->t("Configure how jobs within the pipeline are executed."),
    ];

    $form["jobs"]["max_concurrent_jobs"] = [
      "#type" => "number",
      "#title" => $this->t("Max Concurrent Jobs"),
      "#description" => $this->t("Maximum number of jobs to execute concurrently. Higher values may improve speed but increase resource usage."),
      "#default_value" => $settings["max_concurrent_jobs"] ?? 5,
      "#min" => 1,
      "#max" => 50,
    ];

    $form["jobs"]["job_priority_strategy"] = [
      "#type" => "select",
      "#title" => $this->t("Job Priority Strategy"),
      "#description" => $this->t("How to prioritize jobs within the pipeline."),
      "#options" => [
        "dependency_order" => $this->t("Dependency Order - Execute based on node dependencies"),
        "fifo" => $this->t("FIFO - First in, first out"),
        "priority" => $this->t("Priority - Use job priority values"),
      ],
      "#default_value" => $settings["job_priority_strategy"] ?? "dependency_order",
    ];

    // Retry settings.
    $form["retry"] = [
      "#type" => "details",
      "#title" => $this->t("Retry Settings"),
      "#description" => $this->t("Configure retry behavior for failed jobs."),
      "#open" => FALSE,
    ];

    $form["retry"]["retry_strategy"] = [
      "#type" => "select",
      "#title" => $this->t("Retry Strategy"),
      "#description" => $this->t("How to handle failed jobs in the pipeline."),
      "#options" => [
        "individual" => $this->t("Individual - Retry only the failed job"),
        "pipeline" => $this->t("Pipeline - Restart the entire pipeline on failure"),
        "none" => $this->t("None - Do not retry failed jobs"),
      ],
      "#default_value" => $settings["retry_strategy"] ?? "individual",
    ];

    $form["retry"]["retry_enabled"] = [
      "#type" => "checkbox",
      "#title" => $this->t("Enable Retry"),
      "#description" => $this->t("Automatically retry failed jobs."),
      "#default_value" => $settings["retry"]["enabled"] ?? FALSE,
    ];

    $form["retry"]["retry_max_attempts"] = [
      "#type" => "number",
      "#title" => $this->t("Max Retry Attempts"),
      "#description" => $this->t("Maximum number of retry attempts for failed jobs."),
      "#default_value" => $settings["retry"]["max_attempts"] ?? 3,
      "#min" => 1,
      "#max" => 10,
      "#states" => [
        "visible" => [
          ":input[name=\"orchestrator_settings[retry][retry_enabled]\"]" => ["checked" => TRUE],
        ],
      ],
    ];

    $form["retry"]["retry_delay"] = [
      "#type" => "number",
      "#title" => $this->t("Retry Delay (seconds)"),
      "#description" => $this->t("Delay between retry attempts."),
      "#default_value" => $settings["retry"]["delay"] ?? 5,
      "#min" => 0,
      "#max" => 3600,
      "#states" => [
        "visible" => [
          ":input[name=\"orchestrator_settings[retry][retry_enabled]\"]" => ["checked" => TRUE],
        ],
      ],
    ];

    $form["retry"]["retry_backoff"] = [
      "#type" => "select",
      "#title" => $this->t("Backoff Strategy"),
      "#description" => $this->t("How to increase delay between retry attempts."),
      "#options" => [
        "constant" => $this->t("Constant - Same delay between retries"),
        "linear" => $this->t("Linear - Delay increases linearly"),
        "exponential" => $this->t("Exponential - Delay doubles each retry"),
      ],
      "#default_value" => $settings["retry"]["backoff"] ?? "constant",
      "#states" => [
        "visible" => [
          ":input[name=\"orchestrator_settings[retry][retry_enabled]\"]" => ["checked" => TRUE],
        ],
      ],
    ];

    // Add common fields from parent (priority, timeout).
    $form = parent::buildConfigurationForm($form, $form_state, $settings);

    return $form;
  }

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

    $values = $form_state->getValue("orchestrator_settings") ?? [];

    // Validate pipeline_id is provided when using reuse mode.
    $pipelineMode = $values["pipeline"]["pipeline_mode"] ?? "new";
    $pipelineId = $values["pipeline"]["pipeline_id"] ?? "";

    if ($pipelineMode === "reuse" && empty($pipelineId)) {
      $form_state->setErrorByName(
        "orchestrator_settings][pipeline][pipeline_id",
        $this->t("Pipeline ID is required when using 'Reuse existing pipeline' mode.")
      );
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array $form, FormStateInterface $form_state): array {
    // Get base configuration from parent.
    $config = parent::submitConfigurationForm($form, $form_state);

    // Extract pipeline-specific values.
    $values = $form_state->getValue("orchestrator_settings") ?? [];

    // Pipeline settings.
    $pipelineSettings = $values["pipeline"] ?? [];
    $config["pipeline_mode"] = $pipelineSettings["pipeline_mode"] ?? "new";
    $config["pipeline_id"] = $pipelineSettings["pipeline_id"] ?? "";

    // Job settings.
    $jobSettings = $values["jobs"] ?? [];
    $config["max_concurrent_jobs"] = (int) ($jobSettings["max_concurrent_jobs"] ?? 5);
    $config["job_priority_strategy"] = $jobSettings["job_priority_strategy"] ?? "dependency_order";

    // Retry settings.
    $retrySettings = $values["retry"] ?? [];
    $config["retry_strategy"] = $retrySettings["retry_strategy"] ?? "individual";
    $config["retry"] = [
      "enabled" => (bool) ($retrySettings["retry_enabled"] ?? FALSE),
      "max_attempts" => (int) ($retrySettings["retry_max_attempts"] ?? 3),
      "delay" => (int) ($retrySettings["retry_delay"] ?? 5),
      "backoff" => $retrySettings["retry_backoff"] ?? "constant",
    ];

    return $config;
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultConfiguration(): array {
    return [
      "type" => $this->getPluginId(),
      "priority" => "normal",
      "timeout" => 300,
      "pipeline_mode" => "new",
      "pipeline_id" => "",
      "max_concurrent_jobs" => 5,
      "job_priority_strategy" => "dependency_order",
      "retry_strategy" => "individual",
      "retry" => [
        "enabled" => FALSE,
        "max_attempts" => 3,
        "delay" => 5,
        "backoff" => "constant",
      ],
    ];
  }

}
