<?php

declare(strict_types=1);

namespace Drupal\flowdrop\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Controller for the FlowDrop dashboard.
 *
 * Provides a modern, immersive dashboard experience using FlowDrop UI
 * Components (SDC) for a consistent visual language with the workflow editor.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class FlowDropDashboardController extends ControllerBase {

  /**
   * The module extension list.
   *
   * @var \Drupal\Core\Extension\ModuleExtensionList
   */
  protected ModuleExtensionList $moduleExtensionList;

  /**
   * The route provider.
   *
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected RouteProviderInterface $routeProvider;

  /**
   * Constructs a FlowDropDashboardController.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager service.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
   *   The module handler service.
   * @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
   *   The module extension list service.
   * @param \Drupal\Core\Routing\RouteProviderInterface $routeProvider
   *   The route provider service.
   */
  public function __construct(
    EntityTypeManagerInterface $entityTypeManager,
    ModuleHandlerInterface $moduleHandler,
    ModuleExtensionList $moduleExtensionList,
    RouteProviderInterface $routeProvider,
  ) {
    $this->entityTypeManager = $entityTypeManager;
    $this->moduleHandler = $moduleHandler;
    $this->moduleExtensionList = $moduleExtensionList;
    $this->routeProvider = $routeProvider;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get("entity_type.manager"),
      $container->get("module_handler"),
      $container->get("extension.list.module"),
      $container->get("router.route_provider"),
    );
  }

  /**
   * Renders the main FlowDrop dashboard.
   *
   * @return array<string, mixed>
   *   A render array for the dashboard page.
   */
  public function dashboard(): array {
    $build = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-layout"],
      ],
      "#attached" => [
        "library" => [
          "flowdrop_ui_components/dashboard-layout",
          "flowdrop_ui_components/base",
        ],
      ],
    ];

    // Main content area.
    $build["main"] = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-main", "fd-dashboard-main--constrained"],
      ],
    ];
    // Stats row.
    $build["main"]["stats"] = $this->buildStatsSection();

    // Quick actions.
    $build["main"]["quick_actions"] = $this->buildQuickActionsSection();

    // Navigation sections.
    $build["main"]["navigation"] = $this->buildNavigationSection();

    // Configuration sections.
    $build["main"]["config"] = $this->buildConfigSection();

    // Structure sections.
    $build["main"]["structure"] = $this->buildStructureSection();

    return $build;
  }

  /**
   * Builds the page header.
   *
   * @param string $pageTitle
   *   The page title to display.
   * @param bool $showCreateWorkflow
   *   Whether to show the "Create Workflow" action.
   *
   * @return array<string, mixed>
   *   A render array for the header.
   */
  protected function buildHeader(string $pageTitle, bool $showCreateWorkflow = FALSE): array {
    $primaryAction = NULL;
    if ($showCreateWorkflow && $this->moduleHandler()->moduleExists("flowdrop_workflow")) {
      $url = $this->getRouteUrl("entity.flowdrop_workflow.add_form");
      if ($url !== NULL) {
        $primaryAction = [
          "label" => (string) $this->t("Create Workflow"),
          "url" => $url,
        ];
      }
    }

    // Get module path for assets.
    $modulePath = "/" . $this->moduleExtensionList->getPath("flowdrop_ui_components");

    // Build props array, only including primary_action if it's not NULL.
    $props = [
      "page_title" => $pageTitle,
      "module_path" => $modulePath,
    ];
    if ($primaryAction !== NULL) {
      $props["primary_action"] = $primaryAction;
    }

    return [
      "#type" => "component",
      "#component" => "flowdrop_ui_components:page-header",
      "#props" => $props,
    ];
  }

  /**
   * Builds the statistics section.
   *
   * @return array<string, mixed>
   *   A render array for the stats section.
   */
  protected function buildStatsSection(): array {
    $section = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-section", "fd-animate-in"],
      ],
    ];

    // Collect stat card items for the grid.
    $statItems = [];

    // Operational entities - ordered by workflow lifecycle.
    // 1. Workflows (definitions - the blueprint).
    if ($this->moduleHandler()->moduleExists("flowdrop_workflow")) {
      $count = $this->getEntityCount("flowdrop_workflow");
      $url = $this->getRouteUrl("entity.flowdrop_workflow.collection");
      $statItems["workflows"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Workflows"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getWorkflowIcon(),
        ],
      ];
    }

    // 2. Sessions (playground runs of workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_session")) {
      $entityType = $this->entityTypeManager()->getDefinition("flowdrop_session", FALSE);
      $url = $this->getRouteUrl("entity.flowdrop_session.collection");
      if ($entityType !== NULL && $url !== NULL) {
        $count = $this->getEntityCount("flowdrop_session");
        $statItems["sessions"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:stat-card",
          "#props" => [
            "value" => (string) $count,
            "label" => (string) $this->t("Sessions"),
            "variant" => "default",
            "url" => $url,
            "icon" => $this->getSessionIcon(),
          ],
        ];
      }
    }

    // 3. Pipelines (instances created from workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_pipeline")) {
      $count = $this->getEntityCount("flowdrop_pipeline");
      $url = $this->getRouteUrl("entity.flowdrop_pipeline.collection");
      $statItems["pipelines"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Pipelines"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getPipelineIcon(),
        ],
      ];
    }

    // 4. Jobs (executions of pipelines).
    if ($this->moduleHandler()->moduleExists("flowdrop_job")) {
      $count = $this->getEntityCount("flowdrop_job");
      $url = $this->getRouteUrl("entity.flowdrop_job.collection");
      $statItems["jobs"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Jobs"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getJobIcon(),
        ],
      ];
    }

    // 5. Workflow Snapshots (execution state for resume/handover).
    if ($this->moduleHandler()->moduleExists("flowdrop_runtime")) {
      // Check if the entity type is installed before querying.
      $entityType = $this->entityTypeManager()->getDefinition("flowdrop_workflow_snapshot", FALSE);
      if ($entityType !== NULL) {
        $count = $this->getEntityCount("flowdrop_workflow_snapshot");
        $url = $this->getRouteUrl("entity.flowdrop_workflow_snapshot.collection");
        if ($url !== NULL) {
          $statItems["snapshots"] = [
            "#type" => "component",
            "#component" => "flowdrop_ui_components:stat-card",
            "#props" => [
              "value" => (string) $count,
              "label" => (string) $this->t("Snapshots"),
              "variant" => "default",
              "url" => $url,
              "icon" => $this->getSnapshotIcon(),
            ],
          ];
        }
      }
    }

    // 6. Triggers (automation that starts workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_trigger")) {
      $count = $this->getEntityCount("flowdrop_trigger_config");
      $url = $this->getRouteUrl("entity.flowdrop_trigger_config.collection");
      $statItems["triggers"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Triggers"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getTriggerIcon(),
        ],
      ];
    }

    // 7. Pending Interrupts (HITL — human-in-the-loop).
    if ($this->moduleHandler()->moduleExists("flowdrop_interrupt")) {
      $url = $this->getRouteUrl("flowdrop_interrupt.inbox");
      if ($url !== NULL) {
        $count = $this->getPendingInterruptCount();
        $statItems["interrupts"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:stat-card",
          "#props" => [
            "value" => (string) $count,
            "label" => (string) $this->t("Pending Interrupts"),
            "variant" => $count > 0 ? "warning" : "default",
            "url" => $url,
            "icon" => $this->getInterruptIcon(),
          ],
        ];
      }
    }

    // Configuration entities - building blocks for workflows.
    // 5. Node Types (building blocks used in workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_node_type")) {
      $count = $this->getEntityCount("flowdrop_node_type");
      $url = $this->getRouteUrl("flowdrop.config.node_types");
      $statItems["node_types"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Node Types"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getNodeTypeIcon(),
        ],
      ];
    }

    // 6. Categories (organization of node types).
    if ($this->moduleHandler()->moduleExists("flowdrop_node_category")) {
      $count = $this->getEntityCount("flowdrop_node_category");
      $url = $this->getRouteUrl("entity.flowdrop_node_category.collection");
      $statItems["categories"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:stat-card",
        "#props" => [
          "value" => (string) $count,
          "label" => (string) $this->t("Categories"),
          "variant" => "default",
          "url" => $url,
          "icon" => $this->getCategoryIcon(),
        ],
      ];
    }

    // Use the grid component for consistent responsive behavior.
    $section["stats"] = [
      "#type" => "component",
      "#component" => "flowdrop_ui_components:grid",
      "#props" => [
        "variant" => "stats",
        "stagger" => TRUE,
      ],
      "#slots" => [
        "default" => $statItems,
      ],
    ];

    return $section;
  }

  /**
   * Builds the quick actions section.
   *
   * @return array<string, mixed>
   *   A render array for quick actions.
   */
  protected function buildQuickActionsSection(): array {

    // Collect action link items for the grid.
    $actionItems = [];

    // Execute workflow.
    if ($this->moduleHandler()->moduleExists("flowdrop_runtime")) {
      $url = $this->getRouteUrl("flowdrop.execute");
      if ($url !== NULL) {
        $actionItems["execute_workflow"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Run Workflows"),
            "description" => (string) $this->t("Start a workflow execution with various options"),
            "url" => $url,
            "icon" => $this->getExecuteIcon(),
          ],
        ];
      }

      $url = $this->getRouteUrl("flowdrop_runtime.pipeline_execution");
      if ($url !== NULL) {
        $actionItems["execute_pipeline"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Execute Pipeline"),
            "description" => (string) $this->t("Execute an existing pipeline directly"),
            "url" => $url,
            "icon" => $this->getPipelineIcon(),
          ],
        ];
      }
    }

    // Add Workflow.
    $url = $this->getRouteUrl("flowdrop.workflow.add");
    if ($url !== NULL) {
      $actionItems["add_workflow"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:action-link",
        "#props" => [
          "title" => (string) $this->t("Add Workflow"),
          "description" => (string) $this->t("Create a new workflow"),
          "url" => $url,
          "icon" => $this->getCreateIcon(),
        ],
      ];
    }

    $section = [];

    if ($actionItems) {
      $section = [
        "#type" => "container",
        "#attributes" => [
          "class" => ["fd-section"],
        ],
      ];

      $section["header"] = [
        "#type" => "container",
        "#attributes" => [
          "class" => ["fd-section__header"],
        ],
        "title" => [
          "#type" => "html_tag",
          "#tag" => "h2",
          "#value" => $this->t("Quick Actions"),
          "#attributes" => [
            "class" => ["fd-section__title"],
          ],
        ],
      ];
      // Use the grid component for consistent responsive behavior.
      $section["actions"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:grid",
        "#props" => [
          "variant" => "actions",
          "stagger" => TRUE,
        ],
        "#slots" => [
          "default" => $actionItems,
        ],
      ];
    }
    return $section;
  }

  /**
   * Builds the navigation section with links to all areas.
   *
   * @return array<string, mixed>
   *   A render array for navigation.
   */
  protected function buildNavigationSection(): array {

    // Collect link items for the grid.
    $linkItems = [];

    // Operational entities - ordered by workflow lifecycle.
    // 1. Workflows (definitions - the blueprint).
    if ($this->moduleHandler()->moduleExists("flowdrop_workflow")) {
      $count = $this->getEntityCount("flowdrop_workflow");
      $url = $this->getRouteUrl("entity.flowdrop_workflow.collection");
      if ($url !== NULL) {
        $linkItems["workflows"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Workflows"),
            "description" => (string) $this->t("Create and manage workflow definitions"),
            "url" => $url,
            "icon" => $this->getWorkflowIcon(),
            "badge" => $count,
          ],
        ];
      }
    }

    // 2. Sessions (playground runs of workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_session")) {
      $entityType = $this->entityTypeManager()->getDefinition("flowdrop_session", FALSE);
      $url = $this->getRouteUrl("entity.flowdrop_session.collection");
      if ($entityType !== NULL && $url !== NULL) {
        $count = $this->getEntityCount("flowdrop_session");
        $linkItems["sessions"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Sessions"),
            "description" => (string) $this->t("Browse playground sessions and their runs"),
            "url" => $url,
            "icon" => $this->getSessionIcon(),
            "badge" => $count,
          ],
        ];
      }
    }

    // 3. Pipelines (instances created from workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_pipeline")) {
      $count = $this->getEntityCount("flowdrop_pipeline");
      $url = $this->getRouteUrl("entity.flowdrop_pipeline.collection");
      if ($url !== NULL) {
        $linkItems["pipelines"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Pipelines"),
            "description" => (string) $this->t("View and manage pipeline instances"),
            "url" => $url,
            "icon" => $this->getPipelineIcon(),
            "badge" => $count,
          ],
        ];
      }
    }

    // 4. Jobs (executions of pipelines).
    if ($this->moduleHandler()->moduleExists("flowdrop_job")) {
      $count = $this->getEntityCount("flowdrop_job");
      $url = $this->getRouteUrl("entity.flowdrop_job.collection");
      if ($url !== NULL) {
        $linkItems["jobs"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Jobs"),
            "description" => (string) $this->t("View and manage job executions"),
            "url" => $url,
            "icon" => $this->getJobIcon(),
            "badge" => $count,
          ],
        ];
      }
    }

    // 5. Workflow Snapshots (execution state for resume/handover).
    if ($this->moduleHandler()->moduleExists("flowdrop_runtime")) {
      // Check if the entity type is installed before querying.
      $entityType = $this->entityTypeManager()->getDefinition("flowdrop_workflow_snapshot", FALSE);
      if ($entityType !== NULL) {
        $count = $this->getEntityCount("flowdrop_workflow_snapshot");
        $url = $this->getRouteUrl("entity.flowdrop_workflow_snapshot.collection");
        if ($url !== NULL) {
          $linkItems["snapshots"] = [
            "#type" => "component",
            "#component" => "flowdrop_ui_components:action-link",
            "#props" => [
              "title" => (string) $this->t("Snapshots"),
              "description" => (string) $this->t("View and manage workflow execution snapshots"),
              "url" => $url,
              "icon" => $this->getSnapshotIcon(),
              "badge" => $count,
            ],
          ];
        }
      }
    }

    // 6. Triggers (automation that starts workflows).
    if ($this->moduleHandler()->moduleExists("flowdrop_trigger")) {
      $count = $this->getEntityCount("flowdrop_trigger_config");
      $url = $this->getRouteUrl("entity.flowdrop_trigger_config.collection");
      if ($url !== NULL) {
        $linkItems["triggers"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Triggers"),
            "description" => (string) $this->t("Configure event-based workflow triggers"),
            "url" => $url,
            "icon" => $this->getTriggerIcon(),
            "badge" => $count,
          ],
        ];
      }
    }

    // 7. Pending Interrupts (HITL — human-in-the-loop).
    if ($this->moduleHandler()->moduleExists("flowdrop_interrupt")) {
      $url = $this->getRouteUrl("flowdrop_interrupt.inbox");
      if ($url !== NULL) {
        $linkItems["interrupts"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Pending Interrupts"),
            "description" => (string) $this->t("Review and respond to human-in-the-loop interrupt requests"),
            "url" => $url,
            "icon" => $this->getInterruptIcon(),
          ],
        ];
      }
    }

    if ($linkItems) {
      $section = [
        "#type" => "container",
        "#attributes" => [
          "class" => ["fd-section"],
        ],
      ];

      $section["header"] = [
        "#type" => "container",
        "#attributes" => [
          "class" => ["fd-section__header"],
        ],
        "title" => [
          "#type" => "html_tag",
          "#tag" => "h2",
          "#value" => $this->t("Manage"),
          "#attributes" => [
            "class" => ["fd-section__title"],
          ],
        ],
      ];
      // Use the grid component for consistent responsive behavior.
      $section["links"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:grid",
        "#props" => [
          "variant" => "actions",
          "stagger" => TRUE,
        ],
        "#slots" => [
          "default" => $linkItems,
        ],
      ];

      return $section;
    }
    return [];
  }

  /**
   * Builds the config section with links to all areas.
   *
   * @return array<string, mixed>
   *   A render array for navigation.
   */
  protected function buildConfigSection(): array {
    // Collect link items for Configuration and Structure.
    $linkItems = [];

    // Configuration overview link.
    $configUrl = $this->getRouteUrl("flowdrop.config");
    if ($configUrl !== NULL) {
      $linkItems["config"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:action-link",
        "#props" => [
          "title" => (string) $this->t("Configuration"),
          "description" => (string) $this->t("Manage node types, categories, and settings"),
          "url" => $configUrl,
          "icon" => $this->getSettingsIcon(),
        ],
      ];
    }

    // Structure overview link.
    $structureUrl = $this->getRouteUrl("flowdrop.structure");
    if ($structureUrl !== NULL) {
      $linkItems["structure"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:action-link",
        "#props" => [
          "title" => (string) $this->t("Structure"),
          "description" => (string) $this->t("Manage pipeline types and job types"),
          "url" => $structureUrl,
          "icon" => $this->getStructureIcon(),
        ],
      ];
    }

    if (empty($linkItems)) {
      return [];
    }

    $section = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-section"],
      ],
    ];

    $section["header"] = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-section__header"],
      ],
      "title" => [
        "#type" => "html_tag",
        "#tag" => "h2",
        "#value" => $this->t("Configuration"),
        "#attributes" => [
          "class" => ["fd-section__title"],
        ],
      ],
    ];

    $section["links"] = [
      "#type" => "component",
      "#component" => "flowdrop_ui_components:grid",
      "#props" => [
        "variant" => "actions",
        "stagger" => TRUE,
      ],
      "#slots" => [
        "default" => $linkItems,
      ],
    ];

    return $section;
  }

  /**
   * Builds the structure section with links to entity bundles.
   *
   * Structure is now displayed as a card in the Configuration section,
   * so this method returns an empty array.
   *
   * @return array<string, mixed>
   *   An empty array.
   */
  protected function buildStructureSection(): array {
    return [];
  }

  /**
   * Renders the configuration overview page.
   *
   * @return array<string, mixed>
   *   A render array for the configuration page.
   */
  public function configOverview(): array {
    $build = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-layout"],
      ],
      "#attached" => [
        "library" => [
          "flowdrop_ui_components/dashboard-layout",
          "flowdrop_ui_components/base",
        ],
      ],
    ];

    // Main content.
    $build["main"] = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-main", "fd-dashboard-main--constrained"],
      ],
    ];

    $build["main"]["description"] = [
      "#type" => "html_tag",
      "#tag" => "p",
      "#value" => $this->t("Configure node types, categories, and other FlowDrop settings."),
      "#attributes" => [
        "class" => ["fd-text-secondary", "fd-mb-6"],
      ],
    ];

    // Collect link items for the grid.
    $linkItems = [];

    if ($this->moduleHandler()->moduleExists("flowdrop_node_type")) {
      $url = $this->getRouteUrl("flowdrop.config.node_types");
      if ($url !== NULL) {
        $linkItems["node_types"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Node Types"),
            "description" => (string) $this->t("Configure available node types for workflows"),
            "url" => $url,
            "icon" => $this->getNodeTypeIcon(),
          ],
        ];
      }
    }

    if ($this->moduleHandler()->moduleExists("flowdrop_node_category")) {
      $url = $this->getRouteUrl("entity.flowdrop_node_category.collection");
      if ($url !== NULL) {
        $linkItems["categories"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Categories"),
            "description" => (string) $this->t("Organize node types into categories"),
            "url" => $url,
            "icon" => $this->getCategoryIcon(),
          ],
        ];
      }
    }

    // Trigger settings.
    if ($this->moduleHandler()->moduleExists("flowdrop_trigger")) {
      $url = $this->getRouteUrl("flowdrop.config.triggers");
      if ($url !== NULL) {
        $linkItems["triggers"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Trigger Settings"),
            "description" => (string) $this->t("Configure entity, form, and user event triggers"),
            "url" => $url,
            "icon" => $this->getTriggerIcon(),
          ],
        ];
      }
    }

    // Visual types settings.
    if ($this->moduleHandler()->moduleExists("flowdrop_node_type")) {
      $url = $this->getRouteUrl("flowdrop.config.node_types.visual");
      if ($url !== NULL) {
        $linkItems["visual_types"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Visual Types"),
            "description" => (string) $this->t("Configure node visual appearance options"),
            "url" => $url,
            "icon" => $this->getVisualTypeIcon(),
          ],
        ];
      }
    }

    // Playground settings.
    if ($this->moduleHandler()->moduleExists("flowdrop_playground")) {
      $url = $this->getRouteUrl("flowdrop_playground.settings");
      if ($url !== NULL) {
        $linkItems["playground"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Playground"),
            "description" => (string) $this->t("Configure playground auto-run and behavior settings"),
            "url" => $url,
            "icon" => $this->getPlaygroundIcon(),
          ],
        ];
      }
    }

    // General FlowDrop settings.
    $url = $this->getRouteUrl("flowdrop.settings");
    if ($url !== NULL) {
      $linkItems["settings"] = [
        "#type" => "component",
        "#component" => "flowdrop_ui_components:action-link",
        "#props" => [
          "title" => (string) $this->t("Settings"),
          "description" => (string) $this->t("Configure logging, execution, and real-time settings"),
          "url" => $url,
          "icon" => $this->getSettingsIcon(),
        ],
      ];
    }

    // Use the grid component for consistent responsive behavior.
    $build["main"]["links"] = [
      "#type" => "component",
      "#component" => "flowdrop_ui_components:grid",
      "#props" => [
        "variant" => "actions",
        "stagger" => TRUE,
      ],
      "#slots" => [
        "default" => $linkItems,
      ],
    ];

    return $build;
  }

  /**
   * Renders the structure overview page.
   *
   * @return array<string, mixed>
   *   A render array for the structure page.
   */
  public function structureOverview(): array {
    $build = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-layout"],
      ],
      "#attached" => [
        "library" => [
          "flowdrop_ui_components/dashboard-layout",
          "flowdrop_ui_components/base",
        ],
      ],
    ];

    // Main content.
    $build["main"] = [
      "#type" => "container",
      "#attributes" => [
        "class" => ["fd-dashboard-main", "fd-dashboard-main--constrained"],
      ],
    ];

    $build["main"]["description"] = [
      "#type" => "html_tag",
      "#tag" => "p",
      "#value" => $this->t("Manage pipeline types, job types, and other entity bundles."),
      "#attributes" => [
        "class" => ["fd-text-secondary", "fd-mb-6"],
      ],
    ];

    // Collect link items for the grid.
    $linkItems = [];

    if ($this->moduleHandler()->moduleExists("flowdrop_pipeline")) {
      $url = $this->getRouteUrl("flowdrop.structure.pipeline_types");
      if ($url !== NULL) {
        $linkItems["pipeline_types"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Pipeline Types"),
            "description" => (string) $this->t("Manage pipeline type bundles"),
            "url" => $url,
            "icon" => $this->getPipelineIcon(),
          ],
        ];
      }
    }

    if ($this->moduleHandler()->moduleExists("flowdrop_job")) {
      $url = $this->getRouteUrl("flowdrop.structure.job_types");
      if ($url !== NULL) {
        $linkItems["job_types"] = [
          "#type" => "component",
          "#component" => "flowdrop_ui_components:action-link",
          "#props" => [
            "title" => (string) $this->t("Job Types"),
            "description" => (string) $this->t("Manage job type bundles"),
            "url" => $url,
            "icon" => $this->getJobIcon(),
          ],
        ];
      }
    }

    // Use the grid component for consistent responsive behavior.
    $build["main"]["links"] = [
      "#type" => "component",
      "#component" => "flowdrop_ui_components:grid",
      "#props" => [
        "variant" => "actions",
        "stagger" => TRUE,
      ],
      "#slots" => [
        "default" => $linkItems,
      ],
    ];

    return $build;
  }

  /**
   * Safely gets a URL for a route.
   *
   * @param string $routeName
   *   The route name.
   * @param array<string, mixed> $parameters
   *   Optional route parameters.
   *
   * @return string|null
   *   The URL string, or NULL if the route doesn't exist.
   */
  protected function getRouteUrl(string $routeName, array $parameters = []): ?string {
    try {
      // Check if route exists.
      $this->routeProvider->getRouteByName($routeName);
      return Url::fromRoute($routeName, $parameters)->toString();
    }
    catch (\Exception $e) {
      // Route doesn't exist.
      return NULL;
    }
  }

  /**
   * Gets the count of entities of a given type.
   *
   * @param string $entityTypeId
   *   The entity type ID.
   *
   * @return int
   *   The entity count, or 0 if the entity type doesn't exist or table is
   *   missing.
   */
  protected function getEntityCount(string $entityTypeId): int {
    try {
      // Check if the entity type exists first.
      $entityType = $this->entityTypeManager()->getDefinition($entityTypeId, FALSE);
      if ($entityType === NULL) {
        return 0;
      }

      return (int) $this->entityTypeManager()
        ->getStorage($entityTypeId)
        ->getQuery()
        ->accessCheck(TRUE)
        ->count()
        ->execute();
    }
    catch (\Exception $e) {
      // Handle cases where the database table doesn't exist yet.
      return 0;
    }
  }

  /**
   * Returns the count of pending interrupts for the current user.
   *
   * @return int
   *   The number of pending interrupts.
   */
  protected function getPendingInterruptCount(): int {
    // Optional module integration: use \Drupal::hasService() rather than
    // injecting the service, because flowdrop_interrupt may not be installed.
    // @phpstan-ignore-next-line
    if (!\Drupal::hasService('plugin.manager.flowdrop_interrupt_handler')) {
      return 0;
    }
    try {
      // Count only human-in-the-loop interrupts — the same set the inbox
      // lists. Operational sentinels (sub-workflow execution, pipeline
      // completion) are resolved by the runtime, so counting them here would
      // make this stat diverge from the inbox the card links to.
      // @phpstan-ignore-next-line
      $hitlTypeIds = \Drupal::service('plugin.manager.flowdrop_interrupt_handler')->getHitlTypeIds();
      if ($hitlTypeIds === []) {
        return 0;
      }

      return (int) $this->entityTypeManager()
        ->getStorage('flowdrop_interrupt')
        ->getQuery()
        ->accessCheck(TRUE)
        ->condition('uid', (int) $this->currentUser()->id())
        ->condition('status', 'pending')
        ->condition('type', $hitlTypeIds, 'IN')
        ->count()
        ->execute();
    }
    catch (\Exception $e) {
      return 0;
    }
  }

  /**
   * Returns workflow icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getWorkflowIcon(): string {

    return '<svg xmlns="http://www.w3.org/2000/svg" style="transform: rotate(90deg);" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
  <path stroke-linecap="round" stroke-linejoin="round" d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z" />
</svg>
';
  }

  /**
   * Returns pipeline icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getPipelineIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 18L9 11.25l4.306 4.307a11.95 11.95 0 015.814-5.519l2.74-1.22m0 0l-5.94-2.28m5.94 2.28l-2.28 5.94"/></svg>';
  }

  /**
   * Returns job icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getJobIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M20.25 14.15v4.25c0 .414-.336.75-.75.75h-4.5a.75.75 0 01-.75-.75v-4.25m0 0l4.5-4.5m-4.5 4.5l-4.5 4.5M3.75 9.75h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5a.75.75 0 01.75-.75zm9-3h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5a.75.75 0 01.75-.75z"/></svg>';
  }

  /**
   * Returns node type icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getNodeTypeIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"/></svg>';
  }

  /**
   * Returns execute icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getExecuteIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-1.426 1.526-2.33 2.777-1.643l11.54 6.348c1.554.855 1.554 3.031 0 3.886l-11.54 6.347c-1.251.688-2.777-.217-2.777-1.643V5.653z"/></svg>';
  }

  /**
   * Returns settings icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getCreateIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
  <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
';
  }

  /**
   * Returns settings icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getSettingsIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>';
  }

  /**
   * Returns trigger icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getTriggerIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25l-10.5 11.25L12 13.5H3.75z"/></svg>';
  }

  /**
   * Returns category icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getCategoryIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318a2.25 2.25 0 00.662 1.582l10.5 10.5a2.25 2.25 0 003.182 0l4.318-4.318a2.25 2.25 0 000-3.182l-10.5-10.5A2.25 2.25 0 009.568 3z"/><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z"/></svg>';
  }

  /**
   * Returns visual type icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getVisualTypeIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.53 16.122a3 3 0 00-5.78 1.128 2.25 2.25 0 01-2.4 2.245 4.5 4.5 0 008.4-2.245c0-.399-.078-.78-.22-1.128zm0 0a15.998 15.998 0 003.388-1.62m-5.043-.025a15.994 15.994 0 011.622-3.395m3.42 3.42a15.995 15.995 0 004.764-4.648l3.876-5.814a1.151 1.151 0 00-1.597-1.597L14.146 6.32a15.996 15.996 0 00-4.649 4.763m3.42 3.42a6.776 6.776 0 00-3.42-3.42"/></svg>';
  }

  /**
   * Returns snapshot icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getSnapshotIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z"/><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z"/></svg>';
  }

  /**
   * Returns playground icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getPlaygroundIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z"/></svg>';
  }

  /**
   * Returns session icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getSessionIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z"/></svg>';
  }

  /**
   * Returns interrupt icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getInterruptIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" /></svg>';
  }

  /**
   * Returns structure icon SVG.
   *
   * @return string
   *   The SVG markup.
   */
  protected function getStructureIcon(): string {
    return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"/></svg>';
  }

}
