<?php

/**
 * @file
 * Install, update and uninstall functions for the social_content_block module.
 */

use Drupal\Core\Site\Settings;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Core\Field\FieldConfigInterface;
use Symfony\Component\Yaml\Yaml;

/**
 * Implements hook_modules_installed().
 */
function social_content_block_modules_installed() {
  // When the set of installed modules change, reload the sorting optios.
  _social_content_block_update_sorting_options();
}

/**
 * Update the allowed values in the sorting options field based on plugins.
 */
function _social_content_block_update_sorting_options() {
  /** @var \Drupal\social_content_block\ContentBlockManagerInterface $content_block_manager */
  $content_block_manager = \Drupal::service('plugin.manager.content_block');

  // Retrieve all sort options, removing duplicates and format them to the
  // format of field storage configuration.
  $sort_options = [];

  foreach (array_keys($content_block_manager->getDefinitions()) as $plugin_id) {
    $plugin = $content_block_manager->createInstance($plugin_id);

    foreach ($plugin->supportedSortOptions() as $name => $settings) {
      $sort_options[] = [
        'value' => $name,
        'label' => is_array($settings) ? $settings['label'] : $settings,
      ];
    }
  }

  // Load the existing configuration and update it if it's different.
  $config_name = 'field.storage.block_content.field_sorting';
  $config = \Drupal::configFactory()->getEditable($config_name);
  $config_data = $config->getRawData();

  if ($sort_options !== $config_data['settings']['allowed_values']) {
    $config_data['settings']['allowed_values'] = $sort_options;
    $config->setData($config_data)->save();
    \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
  }
}

/**
 * Add fields for plugin ID and plugin fields to the block content form.
 */
function social_content_block_update_8001(&$sandbox) {
  if (!isset($sandbox['total'])) {
    $sandbox['configs'] = [
      'field.storage.block_content.field_plugin_id' => [
        'id' => 'block_content.field_plugin_id',
        'field_name' => 'field_plugin_id',
        'entity_type' => 'block_content',
        'type' => 'string',
        'settings' => [
          'max_length' => 255,
          'is_ascii' => FALSE,
          'case_sensitive' => FALSE,
        ],
        'cardinality' => 1,
        'translatable' => TRUE,
      ],
      'field.storage.block_content.field_plugin_field' => [
        'id' => 'block_content.field_plugin_field',
        'field_name' => 'field_plugin_field',
        'entity_type' => 'block_content',
        'type' => 'string',
        'settings' => [
          'max_length' => 255,
          'is_ascii' => FALSE,
          'case_sensitive' => FALSE,
        ],
        'cardinality' => 1,
        'translatable' => TRUE,
      ],
      'field.field.block_content.custom_content_list.field_sorting' => 'Select in what order selected content should be displayed',
      'field.field.block_content.custom_content_list.field_plugin_id' => [
        'id' => 'block_content.custom_content_list.field_plugin_id',
        'field_name' => 'field_plugin_id',
        'entity_type' => 'block_content',
        'bundle' => 'custom_content_list',
        'label' => t('Type of content'),
        'description' => 'Select the type of content which will be shown in this block',
        'required' => TRUE,
        'translatable' => FALSE,
        'default_value' => [],
        'default_value_callback' => '',
        'settings' => [],
        'field_type' => 'string',
      ],
      'field.field.block_content.custom_content_list.field_plugin_field' => [
        'id' => 'block_content.custom_content_list.field_plugin_field',
        'field_name' => 'field_plugin_field',
        'entity_type' => 'block_content',
        'bundle' => 'custom_content_list',
        'label' => t('Content selection'),
        'description' => 'Further specify how the content should be selected',
        'required' => FALSE,
        'translatable' => FALSE,
        'default_value' => [],
        'default_value_callback' => '',
        'settings' => [],
        'field_type' => 'string',
      ],
      'core.entity_form_display.block_content.custom_content_list.default' => [
        'langcode' => 'en',
        'status' => TRUE,
        'dependencies' => [
          'config' => [
            'block_content.type.custom_content_list',
            'field.field.block_content.custom_content_list.field_item_amount',
            'field.field.block_content.custom_content_list.field_link',
            'field.field.block_content.custom_content_list.field_plugin_field',
            'field.field.block_content.custom_content_list.field_plugin_id',
            'field.field.block_content.custom_content_list.field_sorting',
            'field.field.block_content.custom_content_list.field_subtitle',
          ],
          'module' => [
            'field_group',
            'link',
          ],
        ],
        'third_party_settings' => [
          'field_group' => [
            'group_display_options' => [
              'children' => [
                'field_sorting',
                'field_item_amount',
              ],
              'parent_name' => '',
              'weight' => 2,
              'format_type' => 'fieldset',
              'format_settings' => [
                'label' => t('Sorting'),
                'description' => '',
                'required_fields' => TRUE,
                'id' => '',
                'classes' => '',
              ],
              'label' => t('Sorting'),
              'region' => 'content',
            ],
            'group_filter_options' => [
              'children' => [
                'field_plugin_id',
                'field_plugin_field',
              ],
              'parent_name' => '',
              'weight' => 1,
              'format_type' => 'fieldset',
              'format_settings' => [
                'label' => t('Content'),
                'description' => '',
                'required_fields' => TRUE,
                'id' => '',
                'classes' => '',
              ],
              'label' => t('Content'),
              'region' => 'content',
            ],
            'group_information' => [
              'children' => [
                'info',
                'field_subtitle',
              ],
              'parent_name' => '',
              'weight' => 0,
              'format_type' => 'fieldset',
              'format_settings' => [
                'id' => '',
                'classes' => '',
                'description' => '',
                'required_fields' => TRUE,
              ],
              'label' => t('Information'),
              'region' => 'content',
            ],
          ],
        ],
        'id' => 'block_content.custom_content_list.default',
        'targetEntityType' => 'block_content',
        'bundle' => 'custom_content_list',
        'mode' => 'default',
        'content' => [
          'field_item_amount' => [
            'weight' => 11,
            'settings' => [
              'placeholder' => '',
            ],
            'third_party_settings' => [],
            'type' => 'number',
            'region' => 'content',
          ],
          'field_link' => [
            'weight' => 3,
            'settings' => [
              'placeholder_url' => '',
              'placeholder_title' => '',
            ],
            'third_party_settings' => [],
            'type' => 'link_default',
            'region' => 'content',
          ],
          'field_plugin_field' => [
            'weight' => 1,
            'settings' => [],
            'third_party_settings' => [],
            'type' => 'content_block_plugin_field',
            'region' => 'content',
          ],
          'field_plugin_id' => [
            'weight' => 0,
            'settings' => [],
            'third_party_settings' => [],
            'type' => 'content_block_plugin_id',
            'region' => 'content',
          ],
          'field_sorting' => [
            'weight' => 10,
            'settings' => [],
            'third_party_settings' => [],
            'type' => 'options_select',
            'region' => 'content',
          ],
          'field_subtitle' => [
            'weight' => 2,
            'settings' => [
              'size' => 60,
              'placeholder' => '',
            ],
            'third_party_settings' => [],
            'type' => 'string_textfield',
            'region' => 'content',
          ],
          'info' => [
            'type' => 'string_textfield',
            'weight' => 1,
            'region' => 'content',
            'settings' => [
              'size' => 60,
              'placeholder' => '',
            ],
            'third_party_settings' => [],
          ],
        ],
        'hidden' => [],
      ],
      'core.entity_view_display.block_content.custom_content_list.default' => [
        'field_plugin_id',
        'field_plugin_field',
      ],
    ];

    $sandbox['total'] = count($sandbox['configs']);
    $sandbox['current'] = 0;
  }

  $names = array_keys($sandbox['configs']);
  $name = (string) $names[$sandbox['current']++];
  $data = $sandbox['configs'][$name];
  $parts = explode('.', $name);

  switch ($parts[0] . '.' . $parts[1]) {
    case 'field.storage':
      FieldStorageConfig::create($data)->save();
      break;

    case 'field.field':
      $field_config = FieldConfig::loadByName($parts[2], $parts[3], $parts[4]);

      if ($field_config instanceof FieldConfigInterface) {
        $field_config->setDescription($data);
      }
      else {
        $field_config = FieldConfig::create($data);
      }

      $field_config->save();
      break;

    case 'core.entity_view_display':
      /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */
      $view_display = \Drupal::service('entity_display.repository')
        ->getViewDisplay($parts[2], $parts[3], $parts[4]);

      foreach ($data as $field) {
        $view_display->removeComponent($field);
      }

      break;

    default:
      \Drupal::service('config.storage')->write($name, $data);
  }

  $sandbox['#finished'] = $sandbox['current'] / $sandbox['total'];
}

/**
 * Fill in fields for plugin ID and plugin fields in existing blocks.
 */
function social_content_block_update_8002(&$sandbox) {
  if (!isset($sandbox['total'])) {
    $sandbox['total'] = \Drupal::entityQuery('block_content')
      ->condition('type', 'custom_content_list')
      ->notExists('field_plugin_id')
      ->accessCheck()
      ->count()
      ->execute();

    if (!$sandbox['total']) {
      return;
    }

    $sandbox['processed'] = 0;
    $sandbox['plugin_id'] = 'topic_content_block';
    $sandbox['limit'] = Settings::get('entity_update_batch_size', 50);

    /** @var \Drupal\social_content_block\ContentBlockManagerInterface $content_block_manager */
    $content_block_manager = \Drupal::service('plugin.manager.content_block');

    $definition = $content_block_manager->getDefinition($sandbox['plugin_id']);
    $sandbox['fields'] = $definition['fields'];
  }

  $entity_ids = \Drupal::entityQuery('block_content')
    ->condition('type', 'custom_content_list')
    ->notExists('field_plugin_id')
    ->accessCheck()
    ->sort('id')
    ->range(0, $sandbox['limit'])
    ->execute();

  $storage = \Drupal::entityTypeManager()->getStorage('block_content');

  foreach ($entity_ids as $entity_id) {
    /** @var \Drupal\block_content\BlockContentInterface $entity */
    $entity = $storage->load($entity_id);

    $entity->field_plugin_id->value = $sandbox['plugin_id'];

    $fields = [];

    foreach ($sandbox['fields'] as $field) {
      if (!$entity->get($field)->isEmpty()) {
        $fields[] = $field;
      }
    }

    if (count($fields) === 1) {
      $entity->field_plugin_field->value = reset($fields);
    }

    $entity->save();
  }

  $sandbox['processed'] += count($entity_ids);

  $sandbox['#finished'] = $sandbox['processed'] / $sandbox['total'];
}

/**
 * Change the weight of fields for correct order.
 */
function social_content_block_update_8003() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $updateHelper->executeUpdate('social_content_block', 'social_content_block_update_8003');

  // Output logged messages to related channel of update execution.
  return $updateHelper->logger()->output();
}

/**
 * Add an extra allowed values to the sorting field.
 */
function social_content_block_update_8004() {
  // Update hook removed and replaced by 8006.
}

/**
 * Move the "Number of items" field to the "Content" section.
 */
function social_content_block_update_8005() {
  /** @var \Drupal\update_helper\UpdaterInterface $update_helper */
  $update_helper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $update_helper->executeUpdate('social_content_block', 'social_content_block_update_8005');

  // Output logged messages to related channel of update execution.
  return $update_helper->logger()->output();
}

/**
 * Add event date as sorting option for events.
 */
function social_content_block_update_8006() {
  _social_content_block_update_sorting_options();
}

/**
 * Change allowed value label.
 */
function social_content_block_update_8801(&$sandbox) {
  // Get content block sorting field.
  $field_purchasers = FieldStorageConfig::loadByName('block_content', 'field_sorting');
  // Get allowed values.
  $allowed_values = $field_purchasers->getSetting('allowed_values');
  // Update label.
  $allowed_values['created'] = 'Last created';
  // Set updated allowed values and save.
  $field_purchasers->setSetting('allowed_values', $allowed_values);
  $field_purchasers->save();
}

/**
 * Add translations support for "Custom content list" custom block fields.
 */
function social_content_block_update_10300() {
  /** @var \Drupal\update_helper\UpdaterInterface $update_helper */
  $update_helper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $update_helper->executeUpdate('social_content_block', __FUNCTION__);

  // Output logged messages to related channel of update execution.
  return $update_helper->logger()->output();
}

/**
 * Add a field for days number.
 */
function social_content_block_update_10301() {
  $entity_type_ids = [
    'field.storage.block_content' => 'field_storage_config',
    'field.field.block_content.custom_content_list' => 'field_config',
  ];

  $path = \Drupal::service('extension.list.module')->getPath('social_content_block') . '/config/static/';

  foreach ($entity_type_ids as $prefix => $entity_type_id) {
    $config_file = $path . $prefix . '.field_duration_10301.yml';
    $settings = Yaml::parseFile($config_file);

    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);

    $storage->createFromStorageRecord($settings)->save();
  }

  /** @var \Drupal\update_helper\UpdaterInterface $update_helper */
  $update_helper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $update_helper->executeUpdate('social_content_block', __FUNCTION__);

  // Output logged messages to related channel of update execution.
  return $update_helper->logger()->output();
}

/**
 * Set limit by days number.
 */
function social_content_block_update_10302(&$sandbox) {
  if (!isset($sandbox['total'])) {
    $sandbox['total'] = \Drupal::entityQuery('block_content')
      ->accessCheck(FALSE)
      ->condition('type', 'custom_content_list')
      ->notExists('field_duration')
      ->count()
      ->execute();

    if (!$sandbox['total']) {
      return;
    }

    $sandbox['sort_by'] = NULL;
    $sandbox['last'] = $sandbox['processed'] = 0;
    $sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
  }

  $entity_ids = \Drupal::entityQuery('block_content')
    ->accessCheck(FALSE)
    ->condition('type', 'custom_content_list')
    ->condition('id', $sandbox['last'], '>')
    ->notExists('field_duration')
    ->sort('id')
    ->sort('field_sorting')
    ->range(0, $sandbox['limit'])
    ->execute();

  $storage = \Drupal::entityTypeManager()->getStorage('block_content');

  /** @var \Drupal\social_content_block\ContentBlockManagerInterface $manager */
  $manager = \Drupal::service('plugin.manager.content_block');

  foreach ($entity_ids as $entity_id) {
    /** @var \Drupal\block_content\BlockContentInterface $entity */
    $entity = $storage->load($entity_id);

    $sort_by = $entity->field_sorting->getValue()[0]['value'];

    if ($sort_by !== $sandbox['sort_by']) {
      $settings = NULL;
      $plugin_id = $entity->field_plugin_id->getValue()[0]['value'];
      if ($manager->hasDefinition($plugin_id)) {
        $plugin = $manager->createInstance($plugin_id);
        $settings = $plugin->supportedSortOptions()[$sort_by];
      }

      if (is_array($settings) && isset($settings['limit']) && !$settings['limit']) {
        $sandbox['duration'] = NULL;
      }
      else {
        if (!isset($sandbox['default'])) {
          $sandbox['default'] = $entity->field_duration->getFieldDefinition()
            ->getDefaultValue($entity)[0]['value'];
        }

        $sandbox['duration'] = $sandbox['default'];
      }

      $sandbox['sort_by'] = $sort_by;
    }

    if ($sandbox['duration']) {
      $entity->field_duration->setValue($sandbox['duration']);
      $entity->save();
    }
  }

  $sandbox['last'] = end($entity_ids);
  $sandbox['processed'] += count($entity_ids);
  $sandbox['#finished'] = $sandbox['processed'] / $sandbox['total'];
}

/**
 * Change widget of sorting field.
 */
function social_content_block_update_10303(): string {
  /** @var \Drupal\update_helper\UpdaterInterface $update_helper */
  $update_helper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $update_helper->executeUpdate('social_content_block', __FUNCTION__);

  // Output logged messages to related channel of update execution.
  return $update_helper->logger()->output();
}

/**
 * Allow to filter content by Flexible groups.
 */
function social_content_block_update_10501(): void {
  // Load the existing configuration.
  $config_name = 'field.field.block_content.custom_content_list.field_group';
  $config = \Drupal::configFactory()->getEditable($config_name);
  $config_data = $config->getRawData();

  if (!empty($config_data['settings']['handler_settings']['target_bundles'])) {
    $config_data['settings']['handler_settings']['target_bundles']['flexible_group'] = 'flexible_group';
    $config->setData($config_data)->save();
    // Make sure we clear cached definitions for the fields.
    \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
  }
}

/**
 * Make the subtitle field optional.
 */
function social_content_block_update_11801(): string {
  /** @var \Drupal\update_helper\UpdaterInterface $update_helper */
  $update_helper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $update_helper->executeUpdate('social_content_block', __FUNCTION__);

  // Output logged messages to related channel of update execution.
  return $update_helper->logger()->output();
}
