<?php

declare(strict_types=1);

namespace Drupal\display_builder_entity_view\Entity;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Theme\Registry;
use Drupal\display_builder\ConfigFormBuilderInterface;
use Drupal\display_builder\InstanceInterface;
use Drupal\display_builder_entity_view\BuilderDataConverter;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay as CoreLayoutBuilderEntityViewDisplay;
use Drupal\ui_patterns\Element\ComponentElementBuilder;
use Drupal\ui_patterns\Entity\SampleEntityGeneratorInterface;
use Drupal\ui_patterns\SourcePluginManager;

/**
 * Provides an entity view display entity that has a display builder.
 *
 * When Layout Builder is activated, extends Layout Builder.
 *
 * @see \Drupal\display_builder_entity_view\Hook\DisplayBuilderEntityViewHook::entityTypeAlter()
 * @see \Drupal\display_builder_entity_view\Entity\EntityViewDisplay
 */
class LayoutBuilderEntityViewDisplay extends CoreLayoutBuilderEntityViewDisplay implements DisplayBuilderEntityDisplayInterface, DisplayBuilderOverridableInterface {

  use EntityViewDisplayTrait;

  /**
   * The source plugin manager.
   */
  protected SourcePluginManager $sourcePluginManager;

  /**
   * The entity type manager.
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The component element builder service.
   */
  protected ComponentElementBuilder $componentElementBuilder;

  /**
   * The sample entity generator.
   */
  protected SampleEntityGeneratorInterface $sampleEntityGenerator;

  /**
   * The theme registry.
   */
  protected Registry $themeRegistry;

  /**
   * The list of modules.
   */
  protected ModuleExtensionList $modules;

  /**
   * The data converter from Manage Display and Layout Builder.
   */
  protected BuilderDataConverter $dataConverter;

  /**
   * The loaded display builder instance.
   */
  protected ?InstanceInterface $instance;

  /**
   * Constructs the LayoutBuilderEntityViewDisplay.
   *
   * @param array $values
   *   The values to initialize the entity with.
   * @param string $entity_type
   *   The entity type ID.
   */
  public function __construct(array $values, $entity_type) {
    $this->entityFieldManager = \Drupal::service('entity_field.manager');
    parent::__construct($values, $entity_type);
    $this->sourcePluginManager = \Drupal::service('plugin.manager.ui_patterns_source');
    $this->entityTypeManager = \Drupal::service('entity_type.manager');
    $this->componentElementBuilder = \Drupal::service('ui_patterns.component_element_builder');
    $this->sampleEntityGenerator = \Drupal::service('ui_patterns.sample_entity_generator');
    $this->themeRegistry = \Drupal::service('theme.registry');
    $this->modules = \Drupal::service('extension.list.module');
    $this->dataConverter = \Drupal::service('display_builder_entity_view.builder_data_converter');
  }

  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage): void {
    // If the update is made from Layout Builder, convert the data and copy
    // to Display Builder's third party settings storage.
    if (isset($this->form_id) && $this->form_id === 'entity_view_display_layout_builder_form') {
      if ($this->getDisplayBuilder()) {
        $this->importFromLayoutBuilder();
      }
    }
    parent::preSave($storage);
  }

  /**
   * Returns the field name used to store overridden displays.
   *
   * @return string|null
   *   The field name used to store overridden displays, or NULL if not set.
   *
   * @see Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface
   */
  public function getDisplayBuilderOverrideField(): ?string {
    return $this->getThirdPartySetting('display_builder', ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY);
  }

  /**
   * Initial import from existing data.
   *
   * @return array
   *   List of UI Patterns sources.
   *
   * @see EntityViewDisplayTrait::initInstanceIfMissing()
   * @see EntityViewDisplay::initialImport()
   */
  protected function initialImport(): array {
    if ($this->getThirdPartySetting('layout_builder', 'enabled')) {
      $sections = $this->getThirdPartySetting('layout_builder', 'sections');

      return $this->dataConverter->convertFromLayoutBuilder($sections);
    }

    // If Layout Builder is not used, import from Manage Display data.
    return $this->dataConverter->convertFromManageDisplay($this->getTargetEntityTypeId(), $this->getTargetBundle(), $this->content);
  }

  /**
   * Import and convert data from layout builder.
   *
   * This is not used for the first import but for the following saves.
   *
   * @see LayoutBuilderEntityViewDisplay::preSave()
   */
  protected function importFromLayoutBuilder(): void {
    if (!$this->getInstanceId()) {
      return;
    }
    $sections = $this->getThirdPartySetting('layout_builder', 'sections');
    $sources = $this->dataConverter->convertFromLayoutBuilder($sections);

    /** @var \Drupal\display_builder\InstanceStorage $storage */
    $storage = $this->entityTypeManager->getStorage('display_builder_instance');
    /** @var \Drupal\display_builder\InstanceInterface $instance */
    $instance = $storage->load($this->getInstanceId());
    $instance->setNewPresent($sources, 'Import from Layout Builder');
    $instance->save();
  }

}
