<?php

declare(strict_types=1);

namespace Drupal\entity_type_extras;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\Element;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Url;

/**
 * Pre-render callbacks for local actions block adjustments.
 */
final class LocalActionsDropbutton implements TrustedCallbackInterface {

  /**
   * Pre-render callback: bündelt Local Actions im Dropbutton auf page_slides.
   */
  public static function preRender(array $build): array {
    $route_name = \Drupal::routeMatch()->getRouteName();
    if ($route_name !== 'view.content.page_slides') {
      return $build;
    }

    if (empty($build['content']) || !is_array($build['content'])) {
      return $build;
    }

    $cacheability = CacheableMetadata::createFromRenderArray($build['content']);
    $attached = $build['content']['#attached'] ?? [];

    // Sammle Link-Items aus dem Render-Array (ohne #properties), sortiert.
    $items = [];
    foreach (Element::children($build['content'], TRUE) as $key) {
      if (is_array($build['content'][$key])) {
        $items[$key] = $build['content'][$key];
      }
    }

    // Nichts tun, wenn es 3 oder weniger Actions sind.
    if (count($items) <= 3) {
      return $build;
    }

    $links = self::localActionsToDropbuttonLinks($items);
    if (count($links) <= 1) {
      return $build;
    }

    $build['content'] = [
      '#type' => 'dropbutton',
      '#links' => $links,
      '#attributes' => [
        'class' => ['entity-type-extras-local-actions-dropbutton'],
      ],
    ];
    if (!empty($attached)) {
      $build['content']['#attached'] = $attached;
    }
    $cacheability->applyTo($build['content']);

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks(): array {
    return ['preRender'];
  }

  /**
   * Extrahiert Dropbutton-Link-Definitionen aus Local-Action-Render-Items.
   *
   * @param array $items
   *   Local action render items.
   *
   * @return array
   *   Array für '#links' in '#type' => 'dropbutton'.
   */
  private static function localActionsToDropbuttonLinks(array $items): array {
    $links = [];

    foreach ($items as $delta => $item) {
      if (isset($item['#access'])) {
        $access = $item['#access'];
        if ($access instanceof AccessResultInterface) {
          if (!$access->isAllowed()) {
            continue;
          }
        }
        elseif ($access === FALSE) {
          continue;
        }
      }

      $title = NULL;
      $url = NULL;
      $options = [];

      // Häufige Fälle:
      // 1) Render-Array enthält '#link' mit title/url (Drupal-Core Builder-Varianten).
      if (isset($item['#link']) && is_array($item['#link'])) {
        $title = $item['#link']['title'] ?? NULL;
        $url = $item['#link']['url'] ?? NULL;
        $options = $item['#link']['localized_options'] ?? [];
      }

      // 2) Render-Array enthält '#title' und '#url'.
      if (!$title && isset($item['#title'])) {
        $title = $item['#title'];
      }
      if (!$url && isset($item['#url'])) {
        $url = $item['#url'];
      }

      // 3) Fallback: manchmal liegen Werte unter 'title'/'url'.
      if (!$title && isset($item['title'])) {
        $title = $item['title'];
      }
      if (!$url && isset($item['url'])) {
        $url = $item['url'];
      }

      // Nur valide Einträge übernehmen.
      if (!$title || !$url) {
        continue;
      }
      if (!$url instanceof Url) {
        continue;
      }

      $links['action_' . $delta] = [
        'title' => $title,
        'url' => $url,
        'weight' => $item['#weight'] ?? 0,
      ] + $options;
    }

    return $links;
  }

}
