<?php

use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface;

/**
 * Migrates existing third party settings and permissions.
 */
function field_permissions_update_8001(&$sandbox) {
  $time = time() + 55;

  // Prepare $sandbox.
  if (empty($sandbox)) {
    $sandbox['entity_type_manager'] = \Drupal::service('entity_type.manager');
    $sandbox['entity_type_bundle_info'] = \Drupal::service('entity_type.bundle.info');
    $sandbox['field_storage_configs'] = \Drupal::entityQuery('field_storage_config')
      ->accessCheck(FALSE)
      ->execute();
    $sandbox['roles'] = \Drupal::entityQuery('user_role')
      ->accessCheck(FALSE)
      ->execute();
    $sandbox['operations'] = ['create', 'edit', 'edit own', 'view', 'view own'];
    $sandbox['remove_perms'] = [];
    $sandbox['max'] = count($sandbox['field_storage_configs']);
  }

  while (time() < $time && !empty($sandbox['field_storage_configs'])) {
    $field_storage = $sandbox['entity_type_manager']
      ->getStorage('field_storage_config')
      ->load(array_pop($sandbox['field_storage_configs']));

    $permission_type = $field_storage->getThirdPartySetting('field_permissions', 'permission_type');
    if ($permission_type) {
      $field_name = $field_storage->getName();
      $entity_type = $field_storage->getTargetEntityTypeId();
      $bundles = array_keys($sandbox['entity_type_bundle_info']->getBundleInfo($entity_type));

      // For each bundle check if there is a field config for that bundle.
      foreach ($bundles as $bundle) {
        $field_config = $sandbox['entity_type_manager']
          ->getStorage('field_config')
          ->load($entity_type .'.'. $bundle .'.'. $field_name);
        // If field config can be loaded then set the permission type.
        if ($field_config) {
          $field_config->setThirdPartySetting('field_permissions', 'permission_type', $permission_type);
          $field_config->save();

          // Go through the roles and add the updated permissions.
          foreach ($sandbox['roles'] as $role_name) {
            /** @var \Drupal\user\RoleInterface $role */
            $role = $sandbox['entity_type_manager']->getStorage('user_role')->load($role_name);
            if (!$role->isAdmin()) {
              foreach ($sandbox['operations'] as $type) {
                $permission = $type . ' ' . $field_name;
                if ($role->hasPermission($permission)) {
                  $sandbox['remove_perms'][$role_name][$permission] = $permission;
                  $role->grantPermission("$type $field_name ($entity_type.$bundle)");
                  $role->save();
                }
              }
            }
          }
        }
      }

      // After bundle fields have been updated unset the field storage setting.
      $field_storage->unsetThirdPartySetting('field_permissions', 'permission_type');
      $field_storage->save();
    }
  }

  // Remove old permissions from roles.
  if (empty($sandbox['field_storage_configs']) && !empty($sandbox['remove_perms'])) {
    foreach ($sandbox['remove_perms'] as $role_name => $perms) {
      /** @var \Drupal\user\RoleInterface $role */
      $role = $sandbox['entity_type_manager']->getStorage('user_role')
        ->load($role_name);

      foreach (array_keys($perms) as $permission) {
        $role->revokePermission($permission);
      }

      $role->save();
    }
  }

  $sandbox['#finished'] = ($sandbox['max'] - count($sandbox['field_storage_configs'])) / $sandbox['max'];
}
