<?php

namespace Drupal\layout_paragraphs_theme_extension\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Theme\Registry;

/**
 * Hook implementations for layout_paragraphs_theme_extension.
 */
class LayoutParagraphsThemeExtensionHooks implements TrustedCallbackInterface {

  /**
   * Implements hook_theme_registry_alter().
   */
  #[Hook('theme_registry_alter')]
  public function themeRegistryAlter(array &$theme_registry): void {
    static $skip_alter = FALSE;
    if ($skip_alter) {
      return;
    }
    $config = \Drupal::config('layout_paragraphs_theme_extension.settings');
    if (!$config->get('display_default_theme')) {
      return;
    }
    $default_theme_name = \Drupal::config('system.theme')->get('default');
    if (!$default_theme_name) {
      return;
    }
    $skip_alter = TRUE;
    $default_theme_registry = $this->getThemeRegistry($default_theme_name);
    $skip_alter = FALSE;
    $paragraph_types = $this->getParagraphTypes();
    // Add base paragraph template from the default theme if present.
    if (!empty($default_theme_registry['paragraph'])) {
      $theme_registry['paragraph'] = $default_theme_registry['paragraph'];
    }
    foreach ($paragraph_types as $type) {
      $template_name = 'paragraph__' . $type;
      if (!empty($default_theme_registry[$template_name])) {
        $theme_registry[$template_name] = $default_theme_registry[$template_name];
      }
    }
    if ($additional_templates_text = $config->get('additional_templates')) {
      $additional_templates = array_filter(array_map('trim', explode("\n", $additional_templates_text)));
      foreach ($additional_templates as $template_name) {
        if (!empty($default_theme_registry[$template_name])) {
          $theme_registry[$template_name] = $default_theme_registry[$template_name];
        }
      }
    }
  }

  /**
   * Implements hook_element_info_alter().
   */
  #[Hook('element_info_alter')]
  public function elementInfoAlter(array &$types): void {
    if (isset($types['layout_paragraphs_builder'])) {
      $types['layout_paragraphs_builder']['#pre_render'][] = '\Drupal\layout_paragraphs_theme_extension\Hook\LayoutParagraphsThemeExtensionHooks::builderPrerender';
    }
  }

  /**
   * Pre-render callback to attach a default theme library.
   *
   * @param array $element
   *   The element to process.
   *
   * @return array
   *   The processed element.
   */
  public static function builderPrerender(array $element): array {
    $config = \Drupal::config('layout_paragraphs_theme_extension.settings');
    if ($config->get('display_default_theme')) {
      $library = trim((string) $config->get('default_theme_library'));
      if ($library !== '') {
        $element['#attached']['library'][] = $library;
      }
    }
    return $element;
  }

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

  /**
   * Gets a theme registry for a given theme name.
   *
   * Note: Uses the internal Registry class, as there is no other way to load
   * the theme registry for a theme other than the currently active one.
   */
  private function getThemeRegistry(string $theme_name): array {
    $root = \Drupal::root();
    $cache = \Drupal::service('cache.default');
    $lock = \Drupal::service('lock');
    $module_handler = \Drupal::service('module_handler');
    $theme_handler = \Drupal::service('theme_handler');
    $theme_initialization = \Drupal::service('theme.initialization');
    $cache_bootstrap = \Drupal::service('cache.bootstrap');
    $extension_list = \Drupal::service('extension.list.module');
    $key_value_factory = \Drupal::service('keyvalue');
    $kernel = \Drupal::service('kernel');

    $registry = new Registry(
      $root,
      $cache,
      $lock,
      $module_handler,
      $theme_handler,
      $theme_initialization,
      $cache_bootstrap,
      $extension_list,
      $kernel,
      $theme_name,
      $key_value_factory
    );

    $theme_manager = \Drupal::service('theme.manager');
    $registry->setThemeManager($theme_manager);
    return $registry->get();
  }

  /**
   * Returns paragraph type machine names.
   */
  private function getParagraphTypes(): array {
    $bundles = \Drupal::service('entity_type.bundle.info')
      ->getBundleInfo('paragraph');
    return array_keys($bundles);
  }

}
