<?php

namespace Drupal\config_translation\FormElement;

use Drupal\Core\Config\Config;
use Drupal\Core\Language\LanguageInterface;
use Drupal\config_translation\Form\ConfigTranslationFormBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\language\Config\LanguageConfigOverride;

/**
 * Defines the list element for the configuration translation interface.
 */
class ListElement implements ElementInterface {

  use StringTranslationTrait;

  /**
   * The schema element this form is for.
   *
   * @var \Drupal\Core\TypedData\TraversableTypedDataInterface
   */
  protected $element;

  /**
   * Constructs a ListElement.
   *
   * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $element
   *   The schema element this form element is for.
   */
  public function __construct(TraversableTypedDataInterface $element) {
    $this->element = $element;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(TypedDataInterface $schema) {
    return new static($schema);
  }

  /**
   * {@inheritdoc}
   */
  public function getTranslationBuild(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, array $parents, $base_key = NULL) {
    $build = [];
    foreach ($this->element as $key => $element) {
      $sub_build = [];
      $element_key = isset($base_key) ? "$base_key.$key" : $key;
      $definition = $element->getDataDefinition();

      if ($form_element = ConfigTranslationFormBase::createFormElement($element)) {
        $element_parents = array_merge($parents, [$key]);
        $sub_build += $form_element->getTranslationBuild($source_language, $translation_language, $source_config[$key], $translation_config[$key], $element_parents, $element_key);

        if (empty($sub_build)) {
          continue;
        }

        // Build the sub-structure and include it with a wrapper in the form if
        // there are any translatable elements there.
        $build[$key] = [];
        if ($element instanceof TraversableTypedDataInterface) {
          $build[$key] = [
            '#type' => 'details',
            '#title' => $this->getGroupTitle($definition, $sub_build),
            '#open' => empty($base_key),
          ];
        }
        $build[$key] += $sub_build;
      }
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfig(Config $base_config, LanguageConfigOverride $config_translation, $config_values, $base_key = NULL) {
    foreach ($this->element as $key => $element) {
      $element_key = isset($base_key) ? "$base_key.$key" : $key;
      if ($form_element = ConfigTranslationFormBase::createFormElement($element)) {
        // Traverse into the next level of the configuration.
        $value = $config_values[$key] ?? NULL;
        $form_element->setConfig($base_config, $config_translation, $value, $element_key);
      }
    }
  }

  /**
   * Returns the title for the 'details' element of a group of schema elements.
   *
   * For some configuration elements the same element structure can be repeated
   * multiple times (for example views displays, filters, etc.). Thus, we try to
   * find a more usable title for the details summary. First check if there is
   * an element which is called title or label and use its value. Then check if
   * there is an element which contains these words and use those. Fall back
   * to the generic definition label if no such element is found.
   *
   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
   *   The definition of the schema element.
   * @param array $group_build
   *   The renderable array for the group of schema elements.
   *
   * @return string
   *   The title for the group of schema elements.
   */
  protected function getGroupTitle(DataDefinitionInterface $definition, array $group_build) {
    $title = '';
    if (isset($group_build['title']['source'])) {
      $title = $group_build['title']['source']['#markup'];
    }
    elseif (isset($group_build['label']['source'])) {
      $title = $group_build['label']['source']['#markup'];
    }
    else {
      foreach (array_keys($group_build) as $title_key) {
        if (isset($group_build[$title_key]['source']) && (str_contains($title_key, 'title') || str_contains($title_key, 'label'))) {
          $title = $group_build[$title_key]['source']['#markup'];
          break;
        }
      }
    }
    return (!empty($title) ? (strip_tags($title) . ' ') : '') . $this->t($definition['label']);
  }

}
