<?php

namespace Drupal\rufi_versions;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueFactory;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\taxonomy_ordinal\TaxonomyOrdinalNumberFormatterInterface;

/**
 * Generates reference revisions values over all content to build new version.
 */
class SnapshotService {

  /**
   * Drupal\Core\Entity\EntityTypeManagerInterface definition.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * Drupal\Core\Config\ConfigFactoryInterface definition.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

  /**
   * Drupal\Core\Config\ImmutableConfig definition.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $rufiStructureConf;

  /**
   * Drupal\Core\KeyValueStore\KeyValueStoreInterface definition.
   *
   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
   */
  protected KeyValueStoreInterface $versionStore;


  /**
   * Drupal\taxonomy_ordinal\TaxonomyOrdinalNumberFormatterInterface definition.
   *
   * @var TaxonomyOrdinalNumberFormatterInterface
   */
  protected TaxonomyOrdinalNumberFormatterInterface $ordinalNumberFormatter;

  /**
   * Constructs a new SnapshotService object.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, KeyValueFactory $keyValueFactory, TaxonomyOrdinalNumberFormatterInterface $ordinal_number_formatter) {
    $this->entityTypeManager = $entity_type_manager;
    $this->configFactory = $config_factory;
    $this->versionStore = $keyValueFactory->get('rufi.rufi_versions');
    $this->rufiStructureConf = $this->configFactory->get('rufi_structure.rufistructureconf');
    $this->ordinalNumberFormatter = $ordinal_number_formatter;
  }

  /**
   * Returns law title.
   *
   * @return string
   *   Get the current title of the contract version.
   */
  public function getTitle() {
    return $this->rufiStructureConf->get('title_section_term_overview_page');
  }

  /**
   * Returns law title.
   *
   * @return string
   *   Get the current description of the contract version.
   */
  public function getDesc() {
    return $this->rufiStructureConf->get('description_section_term_overview_page');
  }

  /**
   * Return number of the next version.
   *
   * @return int|mixed
   *   Returns next version number.
   */
  public function getNextVersionNum() {
    return $this->versionStore->get('version', 0) + 1;
  }

  /**
   * Set number of the recent version.
   *
   * @param int $num
   *   Set the current version number.
   */
  public function setVersionNum(int $num) {
    if ($num > $this->versionStore->get('version', 0)) {
      $this->versionStore->set('version', $num);
    }
  }

  /**
   * Returns term[] shaped as values for field VocabularyCloneFieldType.
   *
   * @return array
   *   Returns array of taxonomy term clones.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getSectionsSnapshot() {
    // Save terms.
    $vid = $this->rufiStructureConf->get('rufi_vocabulary');
    /** @var \Drupal\taxonomy\Entity\Term[] $terms */
    $terms = $this->entityTypeManager->getStorage('taxonomy_term')
      ->loadTree($vid, 0, NULL, TRUE);
    $sections_values = [];
    foreach ($terms as $term) {
      $ordinal_number = $this->ordinalNumberFormatter->getFormattedTermPath($term, 'formatter_medium');
      $sections_values[] = [
        'term_id' => $term->id(),
        'term_parent_id' => $term->parent->target_id,
        'name' => $ordinal_number . ' ' . $term->label(),
        'description' => $term->getDescription() ?: '',
      ];
    }
    return $sections_values;
  }

  /**
   * Returns nodes[] shaped as values for field EntityReferenceRevisions.
   *
   * @param string $type_id
   *   Storage id for the requested entity type.
   * @param array $query
   *   Query params to build the version.
   *
   * @return array
   *   Returns field values for field_type EntityReferenceRevisions.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getEntitySnapshot(string $type_id, array $query): array {
    $rules_value = [];
    /** @var \Drupal\node\NodeInterface[] $nodes */
    $nodes = $this->entityTypeManager->getStorage($type_id)
      ->loadByProperties($query);
    foreach ($nodes as $node) {
      $rules_value[] = [
        'target_id' => $node->id(),
        'target_revision_id' => $node->getRevisionId(),
      ];
    }
    return $rules_value;
  }

  /**
   * Returns rule[] shaped as values for field EntityReferenceRevisions.
   *
   * @return array
   *   Returns field values for field_type EntityReferenceRevisions.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getRulesSnapshot() {
    $query = [
      'type' => 'rule',
      'status' => 1,
      'field_ratified' => 1,
    ];
    return $this->getEntitySnapshot('node', $query);
  }

  /**
   * Returns problem[] shaped as values for field EntityReferenceRevisions.
   *
   * @return array
   *   Returns field values for field_type EntityReferenceRevisions.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getProblemsSnapshot() {
    $query = [
      'type' => 'problem',
      'status' => 1,
    ];
    return $this->getEntitySnapshot('node', $query);
  }

  /**
   * Get arguments[] shaped as values for field EntityReferenceRevisions.
   *
   * @return array
   *   Returns field values for field_type EntityReferenceRevisions.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getArgumentsSnapshot() {
    $query = [
      'status' => 1,
    ];
    return $this->getEntitySnapshot('argument', $query);
  }

}
