<?php

declare(strict_types=1);

namespace Drupal\flowdrop\Plugin\FlowDropNodeProcessor;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\flowdrop\DTO\OutputInterface;
use Drupal\flowdrop\DTO\Output;
use Drupal\flowdrop\DTO\ParameterBagInterface;
use Drupal\flowdrop\DTO\ValidationResult;

/**
 * Abstract base class for FlowDropNode plugins.
 *
 * This class provides common functionality for FlowDropNode plugins and
 * implements default behavior for the FlowDropNodeProcessorInterface methods.
 *
 * All plugins must implement:
 * - getParameterSchema(): Define the data contract (types, defaults,
 *   constraints)
 * - process(ParameterBagInterface $params): The main processing logic
 *
 * LOGGING POLICY:
 * - Routine logging (start, complete, input/output) is handled by the
 *   orchestration layer via ExecutionLogger.
 * - Processors should ONLY log exceptional events worth flagging:
 *   - External service retries/failures
 *   - Fallback usage
 *   - Rate limits
 *   - Unexpected data shapes
 * - For such exceptional logging, inject LoggerChannelFactoryInterface
 *   in the concrete processor that needs it.
 *
 * Note: UI/workflow behavior (connectable, configurable, required) is
 * controlled entirely by the config entity, not by the plugin schema.
 *
 * @see \Drupal\flowdrop\Plugin\FlowDropNodeProcessor\FlowDropNodeProcessorInterface
 * @see \Drupal\flowdrop_runtime\Service\Logging\ExecutionLoggerInterface
 * @see docs/development/flowdrop-node-processor.md
 */
abstract class AbstractFlowDropNodeProcessor extends PluginBase implements FlowDropNodeProcessorInterface, ContainerFactoryPluginInterface {

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "data" => [
          "type" => "mixed",
          "description" => "Output data from the node",
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   *
   * Default implementation returns an empty schema.
   * Subclasses should override this to define their parameters.
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getId(): string {
    return $this->pluginDefinition["id"] ?? $this->getPluginId();
  }

  /**
   * {@inheritdoc}
   */
  public function getName(): string {
    return $this->pluginDefinition["label"] ?? $this->getPluginId();
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription(): string {
    return $this->pluginDefinition["description"] ?? "";
  }

  /**
   * {@inheritdoc}
   */
  public function getVersion(): string {
    return $this->pluginDefinition["version"] ?? "1.0.0";
  }

  /**
   * {@inheritdoc}
   */
  public function validateParams(array $params): ValidationResult {
    // Default implementation - always valid.
    // Subclasses can override for custom validation.
    return ValidationResult::success();
  }

  /**
   * {@inheritdoc}
   *
   * Note: No logging here - orchestration layer handles all routine logging
   * via ExecutionLogger. Exceptions bubble up for the orchestrator to handle.
   */
  public function execute(ParameterBagInterface $params): OutputInterface {
    // Execute the processor's main logic.
    // Exceptions will propagate to the orchestrator which handles logging.
    $result = $this->process($params);

    $output = new Output();
    $output->setStatus("success");

    // Convert the result to output format.
    $output->fromArray($result);

    return $output;
  }

  /**
   * Process the node with unified parameters.
   *
   * This is the template method that subclasses must implement.
   * The execute() method handles the common execution logic,
   * while this method contains the specific node processing logic.
   *
   * IMPORTANT: Do NOT log routine operations here (success messages,
   * input/output logging). The orchestration layer handles this centrally.
   * Only log exceptional events that are worth flagging (retries, fallbacks,
   * external service issues).
   *
   * @param \Drupal\flowdrop\DTO\ParameterBagInterface $params
   *   The resolved parameters (merged from config, workflow values,
   *   and inputs).
   *
   * @return array<string, mixed>
   *   The processed result as an array.
   *
   * @throws \Exception
   *   When processing fails. The orchestrator will log and handle the error.
   */
  abstract protected function process(ParameterBagInterface $params): array;

}
