<?php

declare(strict_types=1);

namespace Drupal\flowdrop_node_type\Controller\Api;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\flowdrop\DTO\NodeMetadata\NodeMetadata;
use Drupal\flowdrop\DTO\NodeMetadata\NodeMetadataBuilder;
use Drupal\flowdrop\DTO\NodeMetadata\NodePort;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\ConfigEditProviderInterface;
use Drupal\flowdrop\Service\FlowDropNodeProcessorPluginManager;
use Drupal\flowdrop_node_type\FlowDropNodeTypeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller for node type API endpoints.
 *
 * This controller uses the Unified Parameter System to derive inputSchema
 * and configSchema from the plugin's parameterSchema combined with the
 * config entity's parameter configuration.
 *
 * API response format:
 * - inputs: derived from parameters with connectable=TRUE
 * - configSchema: derived from parameters with configurable=TRUE
 * - config: default values from entity and plugin schema
 *
 * @see docs/development/flowdrop-node-processor.md
 */
final class NodesController extends ControllerBase {

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

  /**
   * The node executor plugin manager.
   *
   * @var \Drupal\flowdrop\Service\FlowDropNodeProcessorPluginManager
   */
  protected $pluginManager;

  /**
   * Constructs a NodesController.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\flowdrop\Service\FlowDropNodeProcessorPluginManager $pluginManager
   *   The plugin manager.
   */
  public function __construct(
    EntityTypeManagerInterface $entityTypeManager,
    FlowDropNodeProcessorPluginManager $pluginManager,
  ) {
    $this->entityTypeManager = $entityTypeManager;
    $this->pluginManager = $pluginManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get("entity_type.manager"),
      $container->get("flowdrop.node_processor_plugin_manager")
    );
  }

  /**
   * Get all node types.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with all node types.
   */
  public function getNodes(): JsonResponse {
    try {
      $storage = $this->entityTypeManager->getStorage("flowdrop_node_type");
      $entities = $storage->loadMultiple();

      $nodes = [];
      foreach ($entities as $entity) {
        if ($entity instanceof FlowDropNodeTypeInterface && $entity->isEnabled()) {
          $nodeMetadata = $this->buildNodeData($entity);
          if ($nodeMetadata !== NULL) {
            $nodes[] = $nodeMetadata->toArray();
          }
        }
      }

      return new JsonResponse([
        "success" => TRUE,
        "data" => $nodes,
        "count" => count($nodes),
      ]);
    }
    catch (\Exception $e) {
      return new JsonResponse([
        "success" => FALSE,
        "error" => $e->getMessage(),
      ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Get node type metadata.
   *
   * @param string $node_type_id
   *   The node type ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with node type metadata.
   */
  public function getNodeMetadata(string $node_type_id): JsonResponse {
    try {
      $entity = $this->entityTypeManager->getStorage("flowdrop_node_type")->load($node_type_id);

      if (!$entity instanceof FlowDropNodeTypeInterface) {
        return new JsonResponse([
          "success" => FALSE,
          "error" => "Node type not found",
        ], Response::HTTP_NOT_FOUND);
      }

      $nodeMetadata = $this->buildNodeData($entity);
      if ($nodeMetadata === NULL) {
        return new JsonResponse([
          "success" => FALSE,
          "error" => "Failed to build node metadata",
        ], Response::HTTP_INTERNAL_SERVER_ERROR);
      }

      return new JsonResponse([
        "success" => TRUE,
        "data" => [
          "node_type_id" => $node_type_id,
          "metadata" => $nodeMetadata->toArray(),
        ],
      ]);
    }
    catch (\Exception $e) {
      return new JsonResponse([
        "success" => FALSE,
        "error" => $e->getMessage(),
      ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Get node types by category.
   *
   * @param string $category
   *   The category to filter by (plural form from API).
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with filtered node types.
   */
  public function getNodesByCategory(string $category): JsonResponse {
    try {
      $singularCategory = $this->transformCategoryToSingular($category);

      $storage = $this->entityTypeManager->getStorage("flowdrop_node_type");
      $ids = $storage->getQuery()
        ->condition("category", $singularCategory)
        ->accessCheck(FALSE)
        ->execute();
      $entities = $storage->loadMultiple($ids);

      $nodes = [];
      foreach ($entities as $entity) {
        if ($entity instanceof FlowDropNodeTypeInterface && $entity->isEnabled()) {
          $nodeMetadata = $this->buildNodeData($entity);
          if ($nodeMetadata !== NULL) {
            $nodes[] = $nodeMetadata->toArray();
          }
        }
      }

      return new JsonResponse([
        "success" => TRUE,
        "data" => $nodes,
        "count" => count($nodes),
      ]);
    }
    catch (\Exception $e) {
      return new JsonResponse([
        "success" => FALSE,
        "error" => $e->getMessage(),
      ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Validate node type configuration.
   *
   * @param string $node_type_id
   *   The node type ID.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with validation results.
   */
  public function validateConfiguration(string $node_type_id, Request $request): JsonResponse {
    try {
      $content = json_decode($request->getContent(), TRUE);

      if ($content === NULL) {
        return new JsonResponse([
          "success" => FALSE,
          "error" => "Invalid JSON in request body",
        ], Response::HTTP_BAD_REQUEST);
      }

      $config = $content["config"] ?? [];

      $entity = $this->entityTypeManager->getStorage("flowdrop_node_type")->load($node_type_id);

      if (!$entity instanceof FlowDropNodeTypeInterface) {
        return new JsonResponse([
          "success" => FALSE,
          "error" => "Node type not found",
        ], Response::HTTP_NOT_FOUND);
      }

      $executorPlugin = $entity->getExecutorPlugin();
      $parameterSchema = $this->getPluginParameterSchema($executorPlugin);
      $entityParameters = $entity->getParameters();

      $errors = [];
      $properties = $parameterSchema["properties"] ?? [];

      foreach ($properties as $propertyName => $propertySchema) {
        $entityParam = $entityParameters[$propertyName] ?? [];

        // Flags from entity config with system defaults.
        $required = $entityParam["required"] ?? FALSE;
        $configurable = $entityParam["configurable"] ?? FALSE;

        // Only validate configurable parameters in config.
        if ($configurable && $required) {
          if (!array_key_exists($propertyName, $config)) {
            $errors[] = "Required property '{$propertyName}' is missing";
          }
        }

        if (array_key_exists($propertyName, $config)) {
          $value = $config[$propertyName];
          $expectedType = $propertySchema["type"] ?? "mixed";

          if (!$this->validateValueType($value, $expectedType)) {
            $errors[] = "Property '{$propertyName}' must be of type '{$expectedType}'";
          }
        }
      }

      return new JsonResponse([
        "success" => TRUE,
        "data" => [
          "node_type_id" => $node_type_id,
          "validation_result" => [
            "valid" => empty($errors),
            "errors" => $errors,
          ],
        ],
      ]);
    }
    catch (\Exception $e) {
      return new JsonResponse([
        "success" => FALSE,
        "error" => $e->getMessage(),
      ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Build complete node data by merging entity and plugin data.
   *
   * Uses the Unified Parameter System to derive inputSchema and configSchema
   * from the plugin's parameterSchema combined with entity configuration.
   *
   * Note: The visual type is now controlled by the config entity,
   * not the plugin.
   * This allows site builders to choose the appropriate visual representation.
   * When multiple supported types are configured, a "type" parameter is added
   * to the configSchema to allow per-instance type selection.
   *
   * @param \Drupal\flowdrop_node_type\FlowDropNodeTypeInterface $flowdropNodeType
   *   The node type entity.
   *
   * @return \Drupal\flowdrop\DTO\NodeMetadata\NodeMetadata|null
   *   The complete node metadata DTO or NULL if plugin not found.
   */
  protected function buildNodeData(FlowDropNodeTypeInterface $flowdropNodeType): ?NodeMetadata {
    try {
      $executorPlugin = $flowdropNodeType->getExecutorPlugin();

      $inputs = [];
      $outputs = [];
      $configSchema = [];
      $configDefaults = [];

      if ($executorPlugin && $this->pluginManager->hasDefinition($executorPlugin)) {
        $nodeProcessor = $this->pluginManager->createInstance($executorPlugin);

        // Get unified parameter schema from plugin.
        $parameterSchema = $nodeProcessor->getParameterSchema();
        $outputSchema = $nodeProcessor->getOutputSchema();

        // Get entity configuration.
        $entityParameters = $flowdropNodeType->getParameters();
        $entityOutputs = $flowdropNodeType->getOutputs();

        // Derive inputSchema and configSchema
        // from parameterSchema + entity config.
        $derivedSchemas = $this->deriveSchemas($parameterSchema, $entityParameters);
        $inputSchema = $derivedSchemas["inputSchema"];
        $configSchema = $derivedSchemas["configSchema"];
        $configDefaults = $derivedSchemas["configDefaults"];

        // Always add trigger input if not present.
        if (empty($inputSchema["properties"]["trigger"])) {
          $inputSchema["properties"]["trigger"] = [
            "type" => "trigger",
            "title" => "Trigger",
            "required" => FALSE,
          ];
        }

        // Transform schemas to port arrays.
        if (!empty($inputSchema["properties"])) {
          $inputs = $this->transformSchemaToPorts($inputSchema, "input");
        }

        // Filter outputs based on entity configuration.
        $filteredOutputSchema = $this->filterOutputSchema($outputSchema, $entityOutputs);
        if (!empty($filteredOutputSchema["properties"])) {
          $outputs = $this->transformSchemaToPorts($filteredOutputSchema, "output");
        }
      }

      // Get visual type configuration from config entity.
      $visualType = $flowdropNodeType->getVisualType();
      $supportedTypes = $flowdropNodeType->getSupportedVisualTypes();

      // Ensure supportedTypes has at least the default type.
      if (empty($supportedTypes)) {
        $supportedTypes = [$visualType];
      }

      // If multiple types are supported, add a "type" parameter to configSchema
      // so users can change the visual type per node instance.
      if (count($supportedTypes) > 1) {
        $configSchema["properties"]["nodeType"] = [
          "type" => "string",
          "title" => "Visual Type",
          "description" => "Select the visual appearance for this node instance.",
          "enum" => $supportedTypes,
          "default" => $visualType,
        ];
        $configDefaults["type"] = $visualType;
      }

      // Check if the plugin provides configEdit metadata for dynamic
      // configuration. This allows plugins to specify how their configuration
      // UI should be loaded (dynamic schema from API, external edit links,
      // or both). Uses ConfigEditProviderInterface for type-safe interface
      // checking.
      $configEdit = NULL;
      if (isset($nodeProcessor) && $nodeProcessor instanceof ConfigEditProviderInterface) {
        $configEdit = $nodeProcessor->getConfigEdit();
      }

      // Build NodeMetadata using the fluent builder.
      return NodeMetadataBuilder::create()
        ->setId((string) $flowdropNodeType->id())
        ->setName((string) $flowdropNodeType->label())
        ->setType($visualType)
        ->setSupportedTypes($supportedTypes)
        ->setDescription($flowdropNodeType->getDescription())
        ->setCategory($this->transformCategoryToPlural($flowdropNodeType->getCategory()))
        ->setIcon($flowdropNodeType->getIcon())
        ->setColor($flowdropNodeType->getColor())
        ->setPluginVersion($flowdropNodeType->getPluginVersion())
        ->setEnabled($flowdropNodeType->isEnabled())
        ->setTags($flowdropNodeType->getTags())
        ->setExecutorPlugin($executorPlugin)
        ->setInputs($inputs)
        ->setOutputs($outputs)
        ->setConfig($configDefaults)
        ->setConfigSchema($configSchema)
        ->setConfigEdit($configEdit)
        ->build();
    }
    catch (\Exception $e) {
      $this->getLogger("flowdrop")->error("Failed to build node data for @id: @error", [
        "@id" => $flowdropNodeType->id(),
        "@error" => $e->getMessage(),
      ]);
      return NULL;
    }
  }

  /**
   * Derive inputSchema and configSchema from unified parameterSchema.
   *
   * This is the core of the Unified Parameter System's API layer:
   * - Parameters with connectable=TRUE go into inputSchema (input ports)
   * - Parameters with configurable=TRUE go into configSchema (config form)
   * - Default values are extracted for the config object.
   *
   * Flags are controlled entirely by entity configuration with system defaults:
   * - connectable: entity config, else FALSE
   * - configurable: entity config, else TRUE
   * - required: entity config, else FALSE
   *
   * @param array<string, mixed> $parameterSchema
   *   The plugin's parameter schema from getParameterSchema().
   *   Contains standard JSON Schema (type, default, enum, etc.).
   * @param array<string, array<string, mixed>> $entityParameters
   *   The entity's parameter configuration (controls port/form behavior).
   *
   * @return array<string, mixed>
   *   Array with 'inputSchema', 'configSchema', and 'configDefaults'.
   */
  protected function deriveSchemas(array $parameterSchema, array $entityParameters): array {
    $inputProperties = [];
    $configProperties = [];
    $configDefaults = [];
    $inputRequired = [];
    $configRequired = [];

    $properties = $parameterSchema["properties"] ?? [];

    foreach ($properties as $paramName => $paramSchema) {
      // Skip hidden parameters.
      // These are automatically injected by the runtime and should not
      // appear as inputs or config options in the UI.
      $format = $paramSchema["format"] ?? NULL;
      $isHidden = $format === "hidden" || ($paramSchema["hidden"] ?? FALSE) === TRUE;
      if ($isHidden) {
        continue;
      }

      // Get entity-level configuration for this parameter.
      $entityConfig = $entityParameters[$paramName] ?? [];

      // Determine flags from entity config with system defaults.
      // Plugins no longer declare these - entity has full control.
      $configurable = $entityConfig["configurable"] ?? FALSE;
      $connectable = $entityConfig["connectable"] ?? FALSE;
      $required = $entityConfig["required"] ?? FALSE;

      // Get default value (entity overrides schema default).
      $defaultValue = $entityConfig["default"] ?? $paramSchema["default"] ?? NULL;

      // Build clean property schema (without flowdrop metadata).
      $cleanSchema = $this->cleanPropertySchema($paramSchema);

      // Add to inputSchema if connectable (shows as input port).
      if ($connectable) {
        $inputProperties[$paramName] = $cleanSchema;
        if ($required && !$configurable) {
          // Only required via input if no config fallback exists.
          $inputRequired[] = $paramName;
        }
      }

      // Add to configSchema if configurable (shows in config form).
      if ($configurable) {
        $configProperties[$paramName] = $cleanSchema;
        if ($required && !$connectable) {
          // Only required via config if no input fallback exists.
          $configRequired[] = $paramName;
        }

        // Add default value to config object.
        if ($defaultValue !== NULL) {
          $configDefaults[$paramName] = $defaultValue;
        }
      }
    }

    return [
      "inputSchema" => [
        "type" => "object",
        "properties" => $inputProperties,
        "required" => $inputRequired,
      ],
      "configSchema" => [
        "type" => "object",
        "properties" => $configProperties,
        "required" => $configRequired,
      ],
      "configDefaults" => $configDefaults,
    ];
  }

  /**
   * Clean property schema for API response.
   *
   * Returns a copy of the schema suitable for API response.
   * Currently a pass-through since plugins no longer include
   * FlowDrop-specific metadata in their schemas.
   *
   * @param array<string, mixed> $schema
   *   The property schema.
   *
   * @return array<string, mixed>
   *   Clean schema suitable for API response.
   */
  protected function cleanPropertySchema(array $schema): array {
    return $schema;
  }

  /**
   * Filter output schema based on entity configuration.
   *
   * @param array<string, mixed> $outputSchema
   *   The plugin's output schema.
   * @param array<string, array<string, mixed>> $entityOutputs
   *   The entity's output configuration.
   *
   * @return array<string, mixed>
   *   Filtered output schema.
   */
  protected function filterOutputSchema(array $outputSchema, array $entityOutputs): array {
    $filteredProperties = [];
    $properties = $outputSchema["properties"] ?? [];

    foreach ($properties as $outputName => $outputDef) {
      $entityConfig = $entityOutputs[$outputName] ?? [];

      // Default to exposed=true if not configured.
      $exposed = $entityConfig["exposed"] ?? TRUE;

      if ($exposed) {
        $filteredProperties[$outputName] = $outputDef;
      }
    }

    return [
      "type" => "object",
      "properties" => $filteredProperties,
    ];
  }

  /**
   * Get the parameter schema from a plugin.
   *
   * @param string $pluginId
   *   The plugin ID.
   *
   * @return array<string, mixed>
   *   The plugin's parameter schema.
   */
  protected function getPluginParameterSchema(string $pluginId): array {
    try {
      if ($this->pluginManager->hasDefinition($pluginId)) {
        $plugin = $this->pluginManager->createInstance($pluginId);
        return $plugin->getParameterSchema();
      }
    }
    catch (\Exception $e) {
      $this->getLogger("flowdrop")->error("Failed to get parameter schema for @id: @error", [
        "@id" => $pluginId,
        "@error" => $e->getMessage(),
      ]);
    }

    return [];
  }

  /**
   * Transform singular category to plural form for API compatibility.
   *
   * @param string $category
   *   The singular category.
   *
   * @return string
   *   The plural category.
   */
  protected function transformCategoryToPlural(string $category): string {
    $categoryMapping = [
      "trigger" => "triggers",
      "input" => "inputs",
      "output" => "outputs",
      "model" => "models",
      "prompt" => "prompts",
      "processing" => "processing",
      "logic" => "logic",
      "data" => "data",
      "helper" => "helpers",
      "tool" => "tools",
      "vectorstore" => "vectorstores",
      "embedding" => "embeddings",
      "memory" => "memories",
      "agent" => "agents",
      "bundle" => "bundles",
    ];

    return $categoryMapping[$category] ?? $category;
  }

  /**
   * Transform schema to NodePort array format.
   *
   * @param array<string, mixed> $schema
   *   The schema array.
   * @param string $portType
   *   The port type ('input' or 'output').
   *
   * @return array<\Drupal\flowdrop\DTO\NodeMetadata\NodePort>
   *   Array of NodePort objects.
   */
  protected function transformSchemaToPorts(array $schema, string $portType): array {
    $ports = [];
    $properties = $schema["properties"] ?? [];
    $requiredFields = $schema["required"] ?? [];

    foreach ($properties as $propertyName => $propertySchema) {
      $ports[] = new NodePort(
        id: $propertyName,
        name: $propertySchema["title"] ?? $propertyName,
        type: $portType,
        dataType: $this->mapSchemaTypeToDataType($propertySchema["type"] ?? "string"),
        required: in_array($propertyName, $requiredFields, TRUE),
        description: $propertySchema["description"] ?? "",
        defaultValue: $propertySchema["default"] ?? NULL,
      );
    }

    return $ports;
  }

  /**
   * Map JSON schema types to NodeDataType.
   *
   * @param string $schemaType
   *   The JSON schema type.
   *
   * @return string
   *   The NodeDataType.
   */
  protected function mapSchemaTypeToDataType(string $schemaType): string {
    $typeMapping = [
      "string" => "string",
      "number" => "number",
      "integer" => "number",
      "boolean" => "boolean",
      "array" => "array",
      "object" => "json",
      "tool" => "tool",
      "mixed" => "mixed",
      "trigger" => "trigger",
      "branch" => "branch",
    ];

    return $typeMapping[$schemaType] ?? "string";
  }

  /**
   * Transform plural category to singular form for database queries.
   *
   * @param string $category
   *   The plural category.
   *
   * @return string
   *   The singular category.
   */
  protected function transformCategoryToSingular(string $category): string {
    $categoryMapping = [
      "triggers" => "trigger",
      "inputs" => "input",
      "outputs" => "output",
      "models" => "model",
      "prompts" => "prompt",
      "processing" => "processing",
      "logic" => "logic",
      "data" => "data",
      "helpers" => "helper",
      "tools" => "tool",
      "vectorstores" => "vectorstore",
      "embeddings" => "embedding",
      "memories" => "memory",
      "agents" => "agent",
      "bundles" => "bundle",
    ];

    return $categoryMapping[$category] ?? $category;
  }

  /**
   * Validate value type.
   *
   * @param mixed $value
   *   The value to validate.
   * @param string $expectedType
   *   The expected type.
   *
   * @return bool
   *   TRUE if the value matches the expected type.
   */
  protected function validateValueType(mixed $value, string $expectedType): bool {
    return match ($expectedType) {
      "string" => is_string($value),
      "integer" => is_int($value),
      "number" => is_float($value) || is_int($value),
      "boolean" => is_bool($value),
      "array" => is_array($value),
      "object" => is_array($value) || is_object($value),
      "mixed" => TRUE,
      default => TRUE,
    };
  }

  /**
   * Get port configuration for the FlowDrop system.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with port configuration.
   */
  public function getPortConfiguration(): JsonResponse {
    $config = $this->config("flowdrop_node_type.port_config");

    $defaultConfig = [
      "version" => "1.0.0",
      "defaultDataType" => "string",
      "dataTypes" => [
        [
          "id" => "mixed",
          "name" => "Mixed Data",
          "description" => "Mixed data that can be bool, int, string, ...",
          "color" => "var(--color-ref-teal-500)",
          "category" => "temporal",
          "enabled" => TRUE,
        ],
        [
          "id" => "string",
          "name" => "String",
          "description" => "Text data",
          "color" => "var(--color-ref-emerald-500)",
          "category" => "basic",
          "enabled" => TRUE,
        ],
        [
          "id" => "number",
          "name" => "Number",
          "description" => "Numeric data",
          "color" => "var(--color-ref-blue-600)",
          "category" => "numeric",
          "enabled" => TRUE,
        ],
        [
          "id" => "boolean",
          "name" => "Boolean",
          "description" => "True/false values",
          "color" => "var(--color-ref-purple-600)",
          "category" => "logical",
          "enabled" => TRUE,
        ],
        [
          "id" => "array",
          "name" => "Array",
          "description" => "Ordered list of items",
          "color" => "var(--color-ref-amber-500)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "string[]",
          "name" => "String Array",
          "description" => "Array of strings",
          "color" => "var(--color-ref-emerald-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "number[]",
          "name" => "Number Array",
          "description" => "Array of numbers",
          "color" => "var(--color-ref-blue-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "boolean[]",
          "name" => "Boolean Array",
          "description" => "Array of true/false values",
          "color" => "var(--color-ref-purple-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "json[]",
          "name" => "JSON Array",
          "description" => "Array of JSON objects",
          "color" => "var(--color-ref-orange-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "file[]",
          "name" => "File Array",
          "description" => "Array of files",
          "color" => "var(--color-ref-red-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "image[]",
          "name" => "Image Array",
          "description" => "Array of images",
          "color" => "var(--color-ref-pink-400)",
          "category" => "collection",
          "enabled" => TRUE,
        ],
        [
          "id" => "json",
          "name" => "JSON",
          "description" => "JSON structured data",
          "color" => "var(--color-ref-orange-500)",
          "category" => "complex",
          "enabled" => TRUE,
        ],
        [
          "id" => "file",
          "name" => "File",
          "description" => "File data",
          "color" => "var(--color-ref-red-500)",
          "category" => "file",
          "enabled" => TRUE,
        ],
        [
          "id" => "image",
          "name" => "Image",
          "description" => "Image data",
          "color" => "var(--color-ref-pink-500)",
          "category" => "media",
          "enabled" => TRUE,
        ],
        [
          "id" => "audio",
          "name" => "Audio",
          "description" => "Audio data",
          "color" => "var(--color-ref-indigo-500)",
          "category" => "media",
          "enabled" => TRUE,
        ],
        [
          "id" => "video",
          "name" => "Video",
          "description" => "Video data",
          "color" => "var(--color-ref-teal-500)",
          "category" => "media",
          "enabled" => TRUE,
        ],
        [
          "id" => "url",
          "name" => "URL",
          "description" => "Web address",
          "color" => "var(--color-ref-cyan-500)",
          "category" => "special",
          "enabled" => TRUE,
        ],
        [
          "id" => "email",
          "name" => "Email",
          "description" => "Email address",
          "color" => "var(--color-ref-cyan-500)",
          "category" => "special",
          "enabled" => TRUE,
        ],
        [
          "id" => "date",
          "name" => "Date",
          "description" => "Date value",
          "color" => "var(--color-ref-lime-500)",
          "category" => "temporal",
          "enabled" => TRUE,
        ],
        [
          "id" => "datetime",
          "name" => "DateTime",
          "description" => "Date and time value",
          "color" => "var(--color-ref-lime-500)",
          "category" => "temporal",
          "enabled" => TRUE,
        ],
        [
          "id" => "time",
          "name" => "Time",
          "description" => "Time value",
          "color" => "var(--color-ref-lime-500)",
          "category" => "temporal",
          "enabled" => TRUE,
        ],
      ],
      "compatibilityRules" => [],
    ];

    $portConfig = $config->get("config") ?: $defaultConfig;

    return new JsonResponse([
      "success" => TRUE,
      "data" => $portConfig,
      "message" => "Port configuration loaded successfully",
    ]);
  }

}
