<?php

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

use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Core\Database\Database;
use Drupal\user\Entity\Role;
use Drupal\social_post\Entity\Post;
use Drupal\node\Entity\Node;
use Drupal\user\RoleInterface;
use Symfony\Component\Yaml\Yaml;
use Drupal\Core\Config\FileStorage;

/**
 * Implements hook_update_dependencies().
 */
function social_group_update_dependencies() {
  // Necessary because in system_update_8200 all the configuration files are
  // updated and we delete some modules.
  $dependencies['system'][8200] = [
    'social_group' => 8005,
  ];
  // The gnode module is triggering node access rebuild. Lets rebuild it!
  $dependencies['social_group'][8011] = [
    'gnode' => 8005,
  ];
  // Prevent errors when missing VBO module.
  $dependencies['profile'][8002] = [
    'social_group' => 8501,
  ];

  // New config changes should run after the features removal/revert.
  $dependencies['social_group'][8801] = [
    'social_core' => 8805,
  ];

  // New config changes should run after the VBO module changes
  // the structure of views.
  $dependencies['social_group'][11001] = [
    'views_bulk_operations' => 8034,
  ];

  // New config changes should run after the VBO module changes
  // the structure of views.
  $dependencies['social_group'][11002] = [
    'views_bulk_operations' => 8034,
  ];

  // New config changes should run after the VBO module changes
  // the structure of views.
  $dependencies['social_group'][10202] = [
    'views_bulk_operations' => 8034,
  ];

  return $dependencies;
}

/**
 * Implements hook_install().
 *
 * Perform actions related to the installation of social_group.
 */
function social_group_install() {
  // Grant the default permissions for this feature.
  user_role_grant_permissions(
    'verified',
    [
      'create open_group group',
      'create closed_group group',
      'view group stream page',
      'view groups on my profile',
      'view groups on other profiles',
      'create public_group group',
      'flag mute_group_notifications',
      'unflag mute_group_notifications',
    ]
  );
  user_role_grant_permissions(
    'contentmanager',
    [
      'create open_group group',
      'create closed_group group',
      'view group stream page',
      'view groups on my profile',
      'view groups on other profiles',
      'create public_group group',
      'bypass create group access',
      'manage all groups',
      'view node.event.field_content_visibility:group content',
      'view node.topic.field_content_visibility:group content',
      'view node.page.field_content_visibility:group content',
      'access group overview',
      'edit group types',
      'flag mute_group_notifications',
      'unflag mute_group_notifications',
    ]
  );
  user_role_grant_permissions(
    'sitemanager',
    [
      'create open_group group',
      'create closed_group group',
      'view group stream page',
      'view groups on my profile',
      'view groups on other profiles',
      'create public_group group',
      'bypass create group access',
      'manage all groups',
      'view node.event.field_content_visibility:group content',
      'view node.topic.field_content_visibility:group content',
      'view node.page.field_content_visibility:group content',
      'access group overview',
      'edit group types',
      'set social group settings',
      'flag mute_group_notifications',
      'unflag mute_group_notifications',
    ]
  );
  // Add menu items.
  $parents = \Drupal::entityTypeManager()->getStorage('menu_link_content')
    ->loadByProperties(['menu_name' => 'main', 'title' => 'Explore', 'expanded' => TRUE]);
  $parent = reset($parents);
  if ($parent !== FALSE) {
    MenuLinkContent::create([
      'title' => t('All groups'),
      'link' => ['uri' => 'internal:/all-groups'],
      'menu_name' => 'main',
      'expanded' => FALSE,
      'weight' => 20,
      'parent' => 'menu_link_content:' . $parent->uuid(),
    ])->save();
  }

  // Set the view mode to use when shown in activities.
  activity_creator_set_entity_view_mode('group', 'stream');
  activity_creator_set_entity_view_mode('group_content', 'activity');

  // Make sure the admin theme is not used when managing groups.
  $group_settings = \Drupal::configFactory()->getEditable('group.settings');
  $group_settings->set('use_admin_theme', FALSE);
  $group_settings->save();

  // Disable group nodes.
  $view = \Drupal::service('entity_type.manager')->getStorage('view')->load('group_nodes');
  if (!is_null($view)) {
    $view->setStatus(FALSE);
    $view->save();
  }

  // Set module weight.
  module_set_weight('social_group', 2);

  // Since we update group related permissions that touch node content we must
  // also rebuild the node access permissions.
  node_access_rebuild();

  // Add group bulk action to people view.
  _social_group_alter_admin_people_view();
}

/**
 * Function to set permissions.
 */
function _social_group_set_permissions() {
  $roles = Role::loadMultiple();

  /** @var \Drupal\user\Entity\Role $role */
  foreach ($roles as $role) {
    if ($role->id() === 'administrator') {
      continue;
    }

    $permissions = _social_group_get_permissions($role->id());
    user_role_grant_permissions($role->id(), $permissions);
  }
}

/**
 * Build the permissions.
 *
 * @param string $role
 *   The role.
 *
 * @return array
 *   Returns an array containing the permissions.
 */
function _social_group_get_permissions($role) {
  // Anonymous.
  $permissions[RoleInterface::ANONYMOUS_ID] = [
    'access group search',
  ];

  // Authenticated.
  $permissions[RoleInterface::AUTHENTICATED_ID] = array_merge($permissions[RoleInterface::ANONYMOUS_ID], []);

  // Verified.
  $permissions['verified'] = array_merge($permissions[RoleInterface::AUTHENTICATED_ID], [
    'create open_group group',
    'create closed_group group',
    'view group stream page',
    'view groups on my profile',
    'view groups on other profiles',
    'create public_group group',
    'flag mute_group_notifications',
    'unflag mute_group_notifications',
  ]);

  $config = \Drupal::config('entity_access_by_field.settings');
  $disable_public_visibility = $config->get('disable_public_visibility');
  if ($disable_public_visibility === 0) {
    $permissions['verified'][] = 'create public_group group';
  }

  // Content manager.
  $permissions['contentmanager'] = array_merge($permissions['verified'], [
    'bypass create group access',
    'manage all groups',
    'view node.event.field_content_visibility:group content',
    'view node.topic.field_content_visibility:group content',
    'view node.page.field_content_visibility:group content',
    'access group overview',
    'edit group types',
    'access cross-group posting',
  ]);

  // Site manager.
  $permissions['sitemanager'] = array_merge($permissions['contentmanager'], [
    'set social group settings',
  ]);

  if (isset($permissions[$role])) {
    return $permissions[$role];
  }
  return [];
}

/**
 * Install geolocation, geocoder and grolesync module.
 */
function social_group_update_8001() {

  $modules = [
    'geolocation',
    'geocoder',
    'grolesync',
  ];
  \Drupal::service('module_installer')->install($modules);

}

/**
 * Make sure the group nodes view is disabled.
 */
function social_group_update_8002() {
  $view = \Drupal::service('entity_type.manager')->getStorage('view')->load('group_nodes');
  if (!is_null($view)) {
    $view->setStatus(FALSE);
    $view->save();
  }
}

/**
 * Converts group description field type from plain text to formatted text.
 */
function social_group_update_8004(&$sandbox) {

  $entity = 'group';
  $bundle = 'open_group';
  $field_name = 'field_group_description';
  $display_mode = 'default';

  // Add a new column 'format' for description field type.
  $spec = [
    'type' => 'varchar',
    'description' => '',
    'length' => 255,
    'not null' => FALSE,
    'default' => NULL,
  ];
  $schema = Database::getConnection()->schema();
  $table = "{$entity}__{$field_name}";
  $col = "{$field_name}_format";
  $schema->addField($table, $col, $spec);

  // Update the field storage settings.
  $field_storage_id = "{$entity}.$field_name";
  $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config')->load($field_storage_id);

  // Since the usual workflow for field storages do not allow changing the
  // field type, we have to work around it in this case.
  $new_field_storage = $field_storage->toArray();
  $new_field_storage['type'] = 'text_long';
  $new_field_storage['module'] = 'text';
  $new_field_storage['settings'] = [];
  $new_field_storage['dependencies']['module'][] = 'text';
  $new_field_storage = FieldStorageConfig::create($new_field_storage);
  $new_field_storage->original = $new_field_storage;
  $new_field_storage->enforceIsNew(FALSE);
  $new_field_storage->save();

  // Update the field settings.
  $field_id = "{$entity}.{$bundle}.$field_name";
  /** @var \Drupal\field\Entity\FieldConfig $field */
  $field = \Drupal::entityTypeManager()->getStorage('field_config')->load($field_id);
  $new_field = $field->toArray();
  $new_field['field_type'] = 'text_long';
  $new_field['dependencies']['module'][] = 'text';
  $new_field = FieldConfig::create($new_field);
  $new_field->original = $field;
  $new_field->enforceIsNew(FALSE);
  $new_field->save();

  // Update entity view display.
  $display_id = "{$entity}.{$bundle}.$display_mode";
  $view_display = \Drupal::service('entity_type.manager')->getStorage('entity_view_display')->load($display_id);
  if ($component = $view_display->getComponent($field_name)) {
    $view_display->setComponent($field_name, [
      'type' => 'basic_string',
      'settings' => [],
    ] + $component)->save();
  }

  // Update entity form display.
  $form_display_name = 'group.open_group.default';
  $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load($form_display_name);
  if (($component = $form_display->getComponent($field_name)) && $component['type'] == 'string_textarea') {
    $form_display->setComponent($field_name, [
      'type' => 'text_textarea',
      'settings' => [
        'rows' => 5,
        'placeholder' => '',
      ],
    ] + $component)->save();
  }
}

/**
 * Uninstall geocoder and geolocation modules. Remove group geolocation field.
 */
function social_group_update_8005() {
  $modules = [
    'geolocation',
    'geocoder',
  ];

  $config_factory = \Drupal::service('config.factory');

  foreach ($modules as $module) {
    // Remove config.
    $config_factory->getEditable("$module.settings")->delete();

    // Remove cache tables.
    if (Database::getConnection()->schema()->tableExists("cache_$module")) {
      Database::getConnection()->schema()->dropTable("cache_$module");
    }

    // Remove data from system.schema.
    $query = \Drupal::database()->delete('key_value');
    $query->condition('name', $module);
    $query->execute();
  }

  // Remove group geolocation field.
  $config_factory->getEditable('field.field.group.closed_group.field_group_geolocation')->delete();
  $config_factory->getEditable('field.field.group.open_group.field_group_geolocation')->delete();
  $config_factory->getEditable('field.storage.group.field_group_geolocation')->delete();

  // Uninstall geocoder and geolocation modules.
  \Drupal::service('module_installer')->uninstall($modules);
}

/**
 * Add 'closed_group' group type and enable the permission for Authenticated.
 */
function social_group_update_8006() {
  $permissions = _social_group_get_permissions('authenticated');
  user_role_grant_permissions('authenticated', $permissions);
}

/**
 * Uninstall grolesync module (for now, more info: drupal.org/node/2850417).
 */
function social_group_update_8007() {
  $modules = ['grolesync'];
  \Drupal::service('module_installer')->uninstall($modules);
}

/**
 * Update the permissions for social_group.
 */
function social_group_update_8008() {
  _social_group_set_permissions();
}

/**
 * Set the default group configuration and permission for sitemanager.
 */
function social_group_update_8009() {
  $config = \Drupal::configFactory()->getEditable('social_group.settings');
  $config->set('allow_group_selection_in_node', FALSE);
  $config->save();

  // Site manager should have permission to set social group settings.
  $roles = Role::loadMultiple();

  /** @var \Drupal\user\Entity\Role $role */
  foreach ($roles as $role) {
    if ($role->id() !== 'sitemanager') {
      continue;
    }

    $permissions = ['set social group settings'];
    user_role_grant_permissions($role->id(), $permissions);
  }

}

/**
 * Add permissions for public groups.
 */
function social_group_update_8010() {
  /** @var \Drupal\user\Entity\Role $role */
  foreach (Role::loadMultiple() as $role) {
    if ($role->id() === 'anonymous') {
      user_role_grant_permissions($role->id(), ['access group search']);
    }
    else {
      user_role_grant_permissions($role->id(), [
        'create public_group group',
      ]);
    }
  }
}

/**
 * Rebuild node access.
 */
function social_group_update_8011() {
  node_access_rebuild(TRUE);
}

/**
 * Set module weight.
 */
function social_group_update_8012() {
  module_set_weight('social_group', 2);
}

/**
 * Set my groups permissions.
 */
function social_group_update_8013() {
  // Make it so that everyone who has the 'access user profiles' permission,
  // now also get these two new permissions.
  $permissions = [
    'view groups on my profile',
    'view groups on other profiles',
  ];

  /** @var \Drupal\user\Entity\Role $role */
  foreach (Role::loadMultiple() as $role) {
    if ($role->hasPermission('access user profiles')) {
      user_role_grant_permissions($role->id(), $permissions);
    }
  }
}

/**
 * Grant permission to access group overview to contentmanager and sitemanager.
 */
function social_group_update_8014() {
  user_role_grant_permissions('contentmanager', ['access group overview']);
  user_role_grant_permissions('sitemanager', ['access group overview']);
}

/**
 * NOTE: Contains possible data alteration!
 *
 * Change the visibility of all posts placed in an open group, which have
 * visibility public, to community.
 * See: https://www.drupal.org/project/social/issues/2992332#comment-12790905.
 */
function social_group_update_8301(&$sandbox) {
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['items'] = [];
    $sandbox['max'] = 0;

    // First grab all the post IDs that need to change.
    $connection = Database::getConnection();
    $sth = $connection->select('post__field_visibility', 'pv');
    $sth->fields('pv', ['entity_id']);
    $sth->join('post_field_data', 'pd', 'pd.id = pv.entity_id');
    $sth->join('post__field_recipient_group', 'pg', 'pv.entity_id = pg.entity_id');
    $sth->join('groups', 'g', 'pg.field_recipient_group_target_id = g.id');
    $sth->condition('pv.field_visibility_value', '1', '=');
    $sth->condition('g.type', 'open_group', '=');
    // Timestamp is from the moment the commit landed in 8.x-3.x see:
    // https://cgit.drupalcode.org/social/commit/?id=3e465bb1ad927712e22469c193b6e9547ba1c081
    $sth->condition('pd.created', '1534118400', '>');
    $data = $sth->execute();

    $sandbox['items']['post_ids'] = $data->fetchCol();
    $sandbox['max'] = count($sandbox['items']['post_ids']);
  }

  if ($sandbox['items']['post_ids']) {
    $pid = array_shift($sandbox['items']['post_ids']);

    // Load all the entities and re-save them with the correct visibility.
    $post = Post::load($pid);
    /** @var \Drupal\social_post\Entity\Post $post */
    $post->set('field_visibility', '0');
    $post->save();
  }

  $sandbox['progress']++;
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
}

/**
 * NOTE: Contains possible data alteration!
 *
 * Change the visibility of all nodes placed in an open group, which have
 * visibility public, to community.
 * See: https://www.drupal.org/project/social/issues/2992332#comment-12790905.
 */
function social_group_update_8302(&$sandbox) {
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['items'] = [];
    $sandbox['max'] = 0;

    // First grab all the node IDs that need to change.
    $connection = Database::getConnection();
    $sth = $connection->select('group_content_field_data', 'gc');
    $sth->fields('gc', ['entity_id']);
    $sth->join('node__field_content_visibility', 'nv', 'gc.entity_id = nv.entity_id');
    $sth->join('node_field_data', 'nd', 'gc.entity_id = nd.nid');
    $sth->condition('gc.type', 'open_group-group_node-%', 'LIKE');
    $sth->condition('nv.field_content_visibility_value', 'public', '=');
    // Timestamp is from the moment the commit landed in 8.x-3.x see:
    // https://cgit.drupalcode.org/social/commit/?id=3e465bb1ad927712e22469c193b6e9547ba1c081
    $sth->condition('nd.created', '1534118400', '>');
    $data = $sth->execute();

    $sandbox['items']['node_ids'] = $data->fetchCol();
    $sandbox['max'] = count($sandbox['items']['node_ids']);
  }

  if ($sandbox['items']['node_ids']) {
    $pid = array_shift($sandbox['items']['node_ids']);

    // Load all the entities and re-save them with the correct visibility.
    $node = Node::load($pid);
    /** @var \Drupal\node\Entity\Node $node */
    $node->set('field_content_visibility', 'community');
    $node->save();
  }

  $sandbox['progress']++;
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
}

/**
 * Grant permission to edit group types to contentmanager and sitemanager.
 */
function social_group_update_8303() {
  user_role_grant_permissions('contentmanager', ['edit group types']);
  user_role_grant_permissions('sitemanager', ['edit group types']);
}

/**
 * Install gvbo module.
 */
function social_group_update_8501() {
  $modules = ['gvbo', 'social_group_gvbo'];
  \Drupal::service('module_installer')->install($modules);
}

/**
 * Set some extra configuration.
 */
function social_group_update_8502() {
  $config = \Drupal::configFactory()->getEditable('social_group.settings');
  $config->set('allow_hero_selection', FALSE);
  $config->set('default_hero', 'hero');
  $config->save();
}

/**
 * Update view mode for new small teaser style.
 */
function social_group_update_8801() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Add new field for rendered profile entity so we can sort it.
 *
 * Load in a config file from an specific update hook that will never change.
 * Update helper did not update all fields correctly.
 */
function social_group_update_8802() {
  $config_file = \Drupal::service('extension.list.module')->getPath('social_group') . '/config/update/social_group_update_8802.yml';

  if (is_file($config_file)) {
    $settings = Yaml::parse(file_get_contents($config_file));
    if (is_array($settings)) {
      $config = \Drupal::configFactory()
        ->getEditable('views.view.group_manage_members');

      $config->setData($settings)->save(TRUE);
    }
  }
}

/**
 * Install Group Invite & Request modules by default.
 */
function social_group_update_8901() {
  $modules = ['social_group_invite', 'social_group_request'];
  \Drupal::service('module_installer')->install($modules);
}

/**
 * Update group's event views.
 */
function social_group_update_8902() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

  // Update views configuration.
  _social_event_views_update('views.view.group_events', 'default');
}

/**
 * Allow creating groups by default.
 */
function social_group_update_8903() {
  $config = \Drupal::configFactory()->getEditable('social_group.settings');

  if (($setting = $config->get('address_visibility_settings')) !== NULL) {
    $config->set('address_visibility_settings', $setting['street_code_private']);
  }

  $config->set('allow_group_create', TRUE)->save();

  foreach (['contentmanager', 'sitemanager'] as $role) {
    user_role_grant_permissions($role, ['bypass create group access']);
  }
}

/**
 * Make sure flexible group, group type is not required by default.
 */
function social_group_update_8904() {
  $config = \Drupal::configFactory()->getEditable('social_group.settings');
  $config->set('social_group_type_required', FALSE)->save();
}

/**
 * Update form displays for group types according new 10.x UX design.
 */
function social_group_update_8905() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Make group creators as a group managers by default.
 */
function social_group_update_8906() {
  $config_factory = \Drupal::configFactory();

  $group_types = [
    'public_group',
    'open_group',
    'closed_group',
  ];

  foreach ($group_types as $group_type) {
    $config = $config_factory->getEditable('group.type.' . $group_type);
    $config->set('creator_membership', TRUE);

    $creator_roles = $config->get('creator_roles');
    $group_role_id = $group_type . '-group_manager';
    if (!in_array($group_role_id, $creator_roles)) {
      $creator_roles[] = $group_role_id;
      $config->set('creator_roles', $creator_roles);
    }

    $config->save(TRUE);
  }
}

/**
 * Add translation compatibility for Event fields and views.
 */
function social_group_update_8907() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Add translations support for views with groups.
 */
function social_group_update_10201() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Update the configs in the database in accordance with the newest schema.
 */
function social_group_update_10301() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * The Group Events view configuration update.
 */
function social_group_update_10302() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Import flag "Mute Group Notifications" configurations.
 */
function social_group_update_10303() {
  $configs = [
    'flag.flag.mute_group_notifications' => 'flag.flag.mute_group_notifications_10303',
  ];

  $config_storage = \Drupal::service('config.storage');
  $config_path = \Drupal::service('extension.list.module')->getPath('social_group') . '/config/static/';
  $source = new FileStorage($config_path);

  foreach ($configs as $origin_name => $update_name) {
    $config_storage->write($origin_name, $source->read($update_name));
  }
}

/**
 * Update the permissions for social_group.
 */
function social_group_update_10304() {
  $permissions = [
    'flag mute_group_notifications',
    'unflag mute_group_notifications',
  ];

  $roles = Role::loadMultiple();

  /** @var \Drupal\user\Entity\Role $role */
  foreach ($roles as $role) {
    if ($role->id() === 'anonymous') {
      continue;
    }

    user_role_grant_permissions($role->id(), $permissions);
  }
}

/**
 * Update User Groups view configurations.
 */
function social_group_update_10305() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Import exposed block filter configurations of User Groups view.
 */
function social_group_update_10306() {
  $configs = [
    'block.block.exposed_form_groups_page_user_groups' => 'block.block.exposed_form_groups_page_user_groups_10306',
  ];

  $config_storage = \Drupal::service('config.storage');
  $config_path = \Drupal::service('extension.list.module')->getPath('social_group') . '/config/static/';
  $source = new FileStorage($config_path);

  foreach ($configs as $origin_name => $update_name) {
    $config_storage->write($origin_name, $source->read($update_name));
  }
}

/**
 * Update view displays for Group.
 */
function social_group_update_10307() {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Set the default group configuration for cross-posting settings.
 */
function social_group_update_10308() {
  $config = \Drupal::configFactory()->getEditable('social_group.settings');
  $config->set('cross_posting.status', FALSE);
  $config->set('cross_posting.content_types', []);
  $config->save();

  // Grand roles to use cross-posting feature.
  foreach (['sitemanager', 'contentmanager'] as $role_id) {
    user_role_grant_permissions($role_id, ['access cross-group posting']);
  }

  // Install new configs.
  $config_files = [
    'core.entity_view_mode.group_content.activity' => 'core.entity_view_mode.group_content.activity_10308',
    'core.entity_view_display.group_content.closed_group-group_node-event.activity' => 'core.entity_view_display.group_content.closed_group-group_node-event.activity_10308',
    'core.entity_view_display.group_content.closed_group-group_node-topic.activity' => 'core.entity_view_display.group_content.closed_group-group_node-topic.activity_10308',
    'core.entity_view_display.group_content.open_group-group_node-event.activity' => 'core.entity_view_display.group_content.open_group-group_node-event.activity_10308',
    'core.entity_view_display.group_content.open_group-group_node-topic.activity' => 'core.entity_view_display.group_content.open_group-group_node-topic.activity_10308',
    'core.entity_view_display.group_content.public_group-group_node-event.activity' => 'core.entity_view_display.group_content.public_group-group_node-event.activity_10308',
    'core.entity_view_display.group_content.public_group-group_node-topic.activity' => 'core.entity_view_display.group_content.public_group-group_node-topic.activity_10308',
  ];

  $config_storage = \Drupal::service('config.storage');
  $config_path = \Drupal::service('extension.list.module')->getPath('social_group') . '/config/static';
  $source = new FileStorage($config_path);

  foreach ($config_files as $origin_name => $update_name) {
    // Add new message templates.
    $config_storage->write($origin_name, $source->read($update_name));
  }

  // Set display mode for group content to display on stream.
  activity_creator_set_entity_view_mode('group_content', 'activity');
}

/**
 * Update BEF filter in the User Groups view.
 */
function social_group_update_11001(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Update 'views.view.group_manage_members' after VBO module updates.
 */
function social_group_update_11002(array &$sandbox): void {
  $config_file = \Drupal::service('extension.list.module')->getPath('social_group') . '/config/static/views.view.group_manage_members_11002.yml';

  if (is_file($config_file)) {
    $settings = Yaml::parse((string) file_get_contents($config_file));
    if (is_array($settings)) {
      $config = \Drupal::configFactory()
        ->getEditable('views.view.group_manage_members');

      $config->setData($settings)->save(TRUE);
    }
  }
}

/**
 * The emptied hook.
 */
function social_group_update_11003(array &$sandbox): void {
  // Moved to separate sequential update hook.
  // @see: social_group_update_11005
}

/**
 * Change Rendering Language settings for Group Events (Group content) view.
 */
function social_group_update_11004(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Add 'social_group_add_members_to_group_action'.
 *
 * Update 'views.view.user_admin_people' after VBO module updates.
 */
function social_group_update_11005(): void {
  $config = \Drupal::configFactory()->getEditable('views.view.user_admin_people');
  $selected_actions = $config->get('display.default.display_options.fields.views_bulk_operations_bulk_form.selected_actions');
  // We have to check if action is already added.
  $action = array_search('social_group_add_members_to_group_action', array_column($selected_actions, 'action_id'), FALSE);
  // If action is not added we add it.
  if ($action === FALSE) {
    $selected_actions[] = [
      'action_id' => 'social_group_add_members_to_group_action',
    ];
    $config->set('display.default.display_options.fields.views_bulk_operations_bulk_form.selected_actions', $selected_actions);
    $config->save();
  }
}

/**
 * Update exposed filter button name.
 */
function social_group_update_11401(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Add sorting by "title" to "All groups" and "User groups" pages.
 */
function social_group_update_11901(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Disable revisions for groups.
 */
function social_group_update_11902(): void {
  $types = [
    "closed_group",
    "open_group",
    "public_group",
  ];

  foreach ($types as $type) {
    $config = \Drupal::configFactory()->getEditable("group.type." . $type);
    $config->set("new_revision", FALSE);
    $config->save();
  }

}

/**
 * Update the user admin view with our custom action.
 *
 * Action ID: 'social_group_add_members_to_group_action'.
 */
function _social_group_alter_admin_people_view(): void {
  // Get people view config.
  $config = \Drupal::configFactory()->getEditable('views.view.user_admin_people');
  $selected_actions = $config->get('display.default.display_options.fields.views_bulk_operations_bulk_form.selected_actions');

  // Check if already have bulk action.
  if (in_array('social_group_add_members_to_group_action', array_column(array_values($selected_actions), 'action_id'))) {
    return;
  }

  // Add bulk action and save them.
  $selected_actions[] = [
    'action_id' => 'social_group_add_members_to_group_action',
  ];
  $config->set('display.default.display_options.fields.views_bulk_operations_bulk_form.selected_actions', $selected_actions);
  $config->save();
}

/**
 * Cancel limit of outputted roles in views.view.group_manage_members.
 */
function social_group_update_12001(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Search for invalid permission(s) and remove them from existing roles.
 *
 * Permissions to check:
 * - "view node.book.field_content_visibility:group content".
 */
function social_group_update_12002(): void {
  $entity_type_manager = \Drupal::entityTypeManager();
  $all_permissions = array_keys(\Drupal::service('user.permissions')->getPermissions());
  /** @var \Drupal\user\RoleInterface[] $roles */
  $roles = $entity_type_manager->getStorage('user_role')->loadMultiple();

  $permissions_to_check = [
    'view node.book.field_content_visibility:group content',
  ];

  // If permission is not valid (is not on the list of all permissions),
  // we need to revoke it from all existing roles.
  foreach ($permissions_to_check as $permission_to_check) {
    if (!in_array($permission_to_check, $all_permissions)) {
      foreach ($roles as $role) {
        if ($role->hasPermission($permission_to_check)) {
          $role->revokePermission($permission_to_check);
          $role->save();
        }
      }
    }
  }
}

/**
 * Add sort identifier to exposed sorts.
 */
function social_group_update_12003(): string {
  /** @var \Drupal\update_helper\Updater $updater */
  $updater = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $updater->executeUpdate('social_group', 'social_group_update_12003');

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

/**
 * Enable pager limit on the manage members page.
 */
function social_group_update_12101(): string {
  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

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

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

/**
 * Enable the flexible_permissions module.
 */
function social_group_update_12301(): void {
  if (!\Drupal::service('module_handler')->moduleExists('flexible_permissions')) {
    \Drupal::service('module_installer')->install(['flexible_permissions']);
  }
}

/**
 * Add group bulk action to people view.
 */
function social_group_update_12302(): void {
  _social_group_alter_admin_people_view();
}
