<?php

namespace Drupal\small_y_demo_content\EventSubscriber;

use Drupal\block_content\Entity\BlockContent;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigrateImportEvent;
use Drupal\migrate\Event\MigratePostRowSaveEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class SmallYDemoContentMigrationSubscriber.
 *
 * Run functions before migrations start.
 *
 * @package Drupal\small_y_demo_content
 */
class SmallYDemoContentMigrationSubscriber implements EventSubscriberInterface {

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

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * Constructs a new SmallYDemoContentMigrationSubscriber instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database) {
    $this->entityTypeManager = $entity_type_manager;
    $this->database = $database;
  }

  /**
   * Get subscribed events.
   *
   * @inheritdoc
   */
  public static function getSubscribedEvents() {
    $events[MigrateEvents::PRE_IMPORT][] = ['onMigratePreImport'];
    $events[MigrateEvents::POST_IMPORT][] = ['onMigratePostImport'];
    $events[MigrateEvents::POST_ROW_SAVE][] = ['onMigratePostRowSave'];
    return $events;
  }

  /**
   * Do stuff before migration starts.
   *
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   The import event object.
   */
  public function onMigratePreImport(MigrateImportEvent $event) {
    $migration_id = $event->getMigration()->getBaseId();

    if (in_array(
      $migration_id,
        [
          'small_y_demo_menu_link_main',
        ]
      )
    ) {
      $map = [
        'small_y_demo_menu_link_main' => 'main',
      ];
      // Make cleanup the menu before import the new links.
      $this->removeMenuItems($map[$migration_id]);
    }
  }

  /**
   * Remove menu items by menu name.
   *
   * @param string $menu_name
   *
   * @return void
   */
  private function removeMenuItems(string $menu_name) {
    $menu_links = $this->entityTypeManager->getStorage('menu_link_content')
      ->loadByProperties(
        [
          'menu_name' => $menu_name,
        ]
      );

    if (is_array($menu_links)) {
      foreach ($menu_links as $menu_link) {
        $menu_link->delete();
      }
    }
  }

  /**
   * Do stuff after migration import.
   *
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   The import event object.
   */
  public function onMigratePostImport(MigrateImportEvent $event) {
    $migration_id = $event->getMigration()->getBaseId();

    if ($migration_id === 'small_y_demo_menu_link_main') {
      $this->addMenuCtaBlockFieldtoMenuItems();
      $this->addDemoCtaBlockToMenuItem();
    }
  }

  /**
   * Fix inline_block_usage after each node is migrated.
   *
   * @param \Drupal\migrate\Event\MigratePostRowSaveEvent $event
   *   The post row save event object.
   */
  public function onMigratePostRowSave(MigratePostRowSaveEvent $event) {
    $migration = $event->getMigration();
    $destination_config = $migration->getDestinationConfiguration();

    // Only process node migrations.
    if (empty($destination_config['plugin']) || $destination_config['plugin'] !== 'entity:node') {
      return;
    }

    // Get the node ID from destination IDs.
    $destination_ids = $event->getDestinationIdValues();
    if (empty($destination_ids[0])) {
      return;
    }

    $nid = $destination_ids[0];
    $this->fixInlineBlockUsageForNode($nid);
  }

  /**
   * We have to attach extra field to the created menu items after import.
   */
  private function addMenuCtaBlockFieldtoMenuItems() {
      \Drupal::entityTypeManager()->clearCachedDefinitions();
      $menus = \Drupal::entityTypeManager()
        ->getStorage('menu')
        ->loadMultiple();
      /** @var \Drupal\menu_item_extras\Service\MenuLinkContentService $mlc_helper */
      $mlc_helper = \Drupal::service('menu_item_extras.menu_link_content_helper');
      $mlc_helper->doEntityUpdate();
      $mlc_helper->updateMenuLinkContentBundle();
      $mlc_helper->installViewModeField();
      if (!empty($menus)) {
        foreach ($menus as $menu_id => $menu) {
          $mlc_helper->updateMenuItemsBundle($menu_id);
        }
      }
      $mlc_helper->doBundleFieldUpdate();
    }

    /**
     * Find and add created Menu CTA block to menu item.
     */
    private function addDemoCtaBlockToMenuItem() {
      $blocks = \Drupal::entityQuery('block_content')
        ->accessCheck(FALSE)
        // We've created a block with this info field.
        ->condition('info', 'Demo Menu CTA block')
        ->execute();
      $block = BlockContent::load(reset($blocks));
      if ($block) {
        $menu_links = \Drupal::entityTypeManager()
          ->getStorage('menu_link_content')
          ->loadByProperties(['title' => 'Who We Are']);
        foreach ($menu_links as $menu_link) {
          if ($menu_link->link->uri === 'internal:#') {
            $menu_link->field_cta_block->target_id = $block->id();
            $menu_link->save();
          }
        }
      }
    }

  /**
   * Fix inline_block_usage for a single migrated node.
   *
   * When nodes with Layout Builder sections are created via migrations,
   * the inline_block_usage table is not populated. This causes access
   * issues when editing inline blocks with Media Library.
   *
   * @param int $nid
   *   The node ID to process.
   */
  private function fixInlineBlockUsageForNode(int $nid): void {
    $node = $this->entityTypeManager->getStorage('node')->load($nid);
    if (!$node || !$node->hasField('layout_builder__layout')) {
      return;
    }

    $sections = $node->get('layout_builder__layout')->getValue();
    foreach ($sections as $section_data) {
      if (empty($section_data['section'])) {
        continue;
      }
      /** @var \Drupal\layout_builder\Section $section */
      $section = $section_data['section'];
      $components = $section->getComponents();

      foreach ($components as $component) {
        $config = $component->get('configuration');
        if (empty($config['id']) || strpos($config['id'], 'inline_block:') !== 0) {
          continue;
        }

        $block_revision_id = $config['block_revision_id'] ?? NULL;
        if (!$block_revision_id) {
          continue;
        }

        $block_content = $this->entityTypeManager
          ->getStorage('block_content')
          ->loadRevision($block_revision_id);

        if (!$block_content) {
          continue;
        }

        $existing = $this->database->select('inline_block_usage', 'ibu')
          ->fields('ibu')
          ->condition('block_content_id', $block_content->id())
          ->execute()
          ->fetchAssoc();

        if ($existing) {
          continue;
        }

        $this->database->insert('inline_block_usage')
          ->fields([
            'block_content_id' => $block_content->id(),
            'layout_entity_type' => 'node',
            'layout_entity_id' => $nid,
          ])
          ->execute();
      }
    }
  }

}
