<?php

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

declare(strict_types=1);

use Drupal\acquia_dam\Entity\ImageAltTextField;
use Drupal\acquia_dam\Entity\ManagedFileField;
use Drupal\acquia_dam\Entity\ManagedImageField;
use Drupal\acquia_dam\Entity\MediaExpiryDateField;
use Drupal\acquia_dam\Entity\MediaSourceField;
use Drupal\acquia_dam\FormatAllowedHtmlModifier;
use Drupal\acquia_dam\Plugin\media\Source\Asset;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
use Drupal\Core\Url;
use Drupal\filter\Entity\FilterFormat;
use Drupal\media\MediaTypeInterface;
use Drupal\views\Entity\View;

/**
 * Implements hook_schema().
 */
function acquia_dam_schema() {
  $schema = [];
  $schema['acquia_dam_integration_link_tracking'] = [
    'description' => 'Table for tracking DAM integration link IDs.',
    'fields' => [
      'entity_uuid' => [
        'type' => 'char',
        'description' => 'Parent entity UUID.',
        'length' => 36,
        'not null' => TRUE,
        'default' => '',
      ],
      'entity_type' => [
        'type' => 'varchar',
        'description' => 'Parent entity type.',
        'default' => '',
        'not null' => FALSE,
        'length' => 36,
      ],
      'asset_uuid' => [
        'type' => 'char',
        'description' => 'Asset UUID.',
        'length' => 36,
        'not null' => TRUE,
        'default' => '',
      ],
      'integration_link_id' => [
        'type' => 'varchar',
        'description' => 'Integration link UUID generated by DAM.',
        'default' => '',
        'not null' => TRUE,
        'length' => 36,
      ],
      'path' => [
        'type' => 'varchar',
        'description' => 'The path for the integration link.',
        'default' => '',
        'not null' => TRUE,
        'length' => 255,
      ],
      'created' => [
        'type' => 'varchar',
        'description' => "The integration created.",
        'default' => '',
        'not null' => TRUE,
        'length' => 36,
      ],
    ],
    'primary key' => ['integration_link_id'],
    'indexes' => [
      'entity' => ['entity_uuid', 'integration_link_id'],
    ],
    'unique keys' => [
      'integration_link_id' => ['integration_link_id'],
      'entity_uuid_entity_type_asset_uuid' => [
        'entity_uuid',
        'entity_type',
        'asset_uuid',
      ],
    ],
  ];

  $schema['acquia_dam_integration_link_aggregate'] = [
    'fields' => [
      'asset_uuid' => [
        'type' => 'char',
        'description' => 'Asset UUID.',
        'length' => 36,
        'not null' => TRUE,
        'default' => '',
      ],
      'usage_count' => [
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
    ],
    'primary key' => ['asset_uuid'],
  ];

  return $schema;
}

/**
 * Implements hook_install().
 */
function acquia_dam_install($is_syncing) {
  $state = \Drupal::state();
  $state->set('acquia_dam.last_update_check', \Drupal::time()->getCurrentTime());

  if (!$is_syncing) {
    \Drupal::messenger()->addStatus(t('The Acquia DAM module has been installed. You need to <a href=":link">configure the module</a> for others to make use of it.', [':link' => Url::fromRoute('acquia_dam.config')->toString()]));

    foreach (FilterFormat::loadMultiple() as $filter_format) {
      \Drupal::classResolver()
        ->getInstanceFromDefinition(FormatAllowedHtmlModifier::class)
        ->process($filter_format);
      $filter_format->save();
    }
  }

  // Register bundle fields.
  \Drupal::service('acquia_dam.bundle_field_map')->registerBundleFields();

  // Update acquia_dam_expiry_date field to use BIGINT for Y2038 compatibility.
  \Drupal::service('acquia_dam.y2038_compatibility')->updateExpiryDateFieldToBigint();

  $module_handler = \Drupal::service('module_handler');
  $config_factory = \Drupal::configFactory();
  if (!$module_handler->moduleExists('media_acquiadam')) {
    return;
  }
  // Zeroing in on the schema data check of the domain key as it contain
  // only in the 2.x version.
  $media_acquidam_config = \Drupal::service('config.typed')->getDefinition('media_acquiadam.settings');
  if (array_key_exists('domain', $media_acquidam_config['mapping'])) {
    $media_acquiadam_settings = $config_factory->get('media_acquiadam.settings');
    $acquia_dam_settings = $config_factory->getEditable('acquia_dam.settings');
    // Setting the domain.
    $domain_url = $media_acquiadam_settings->get('domain');
    $acquia_dam_settings->set('domain', $domain_url);
    $acquia_dam_settings->save();
    // Pushing token into the state.
    $token = $media_acquiadam_settings->get('token');
    $state->set('acquia_dam_token', $token);

    // Handling the user data.
    $user_data = \Drupal::service('user.data');
    $auth_service = \Drupal::service('acquia_dam.authentication_service');
    $user_ids = \Drupal::entityQuery('user')->accessCheck(FALSE)->execute();
    foreach ($user_ids as $user_id) {
      $account = $user_data->get('media_acquiadam', $user_id, 'account');
      if (isset($account['acquiadam_username']) && isset($account['acquiadam_token'])) {
        $auth_service->setUserData(
          (int) $user_id,
          [
            'acquia_dam_username' => $account['acquiadam_username'],
            'acquia_dam_token' => $account['acquiadam_token'],
          ]
        );
      }
    }
  }
}

/**
 * Implements hook_uninstall().
 */
function acquia_dam_uninstall() {
  $keys_to_delete = [
    'acquia_dam_token',
    'acquia_dam_username',
    'acquia_dam.last_update_check',
    'acquia_dam_refresh_token',
  ];

  $state = \Drupal::state();

  foreach ($keys_to_delete as $key) {
    if ($state->get($key)) {
      $state->delete($key);
    }
  }
}

/**
 * Imports configuration changes since RC1.
 */
function acquia_dam_update_9001() {

  $configuration_map = [
    'media_type' => [
      'media.type.acquia_dam_image_asset',
      'media.type.acquia_dam_spinset_asset',
      'media.type.acquia_dam_documents_asset',
    ],
    'entity_view_display' => [
      'core.entity_view_display.media.acquia_dam_image_asset.default',
      'core.entity_view_display.media.acquia_dam_image_asset.media_library',
      'core.entity_view_display.media.acquia_dam_spinset_asset.default',
      'core.entity_view_display.media.acquia_dam_spinset_asset.media_library',
      'core.entity_view_display.media.acquia_dam_documents_asset.default',
      'core.entity_view_display.media.acquia_dam_documents_asset.media_library',
    ],
  ];
  $source = new FileStorage(__DIR__ . '/config/install');
  foreach ($configuration_map as $config_type => $configs) {
    $entity_storage = \Drupal::entityTypeManager()->getStorage($config_type);
    foreach ($configs as $config) {
      $entity = $entity_storage->createFromStorageRecord($source->read($config));
      $entity->save();
    }
  }
}

/**
 * Update config schema for settings and set last update check in state storage.
 */
function acquia_dam_update_9002() {
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('acquia_dam.settings');
  $config->set('allowed_image_styles', []);
  $config->save(TRUE);

  $state = \Drupal::state();
  $state->set('acquia_dam.last_update_check', \Drupal::time()->getCurrentTime());
}

/**
 * Update database schema and configuration.
 */
function acquia_dam_update_9003() {
  _acquia_dam_add_dam_content_views();

  $config = [
    'fields' => [
      'asset_uuid' => [
        'type' => 'char',
        'description' => 'Asset UUID.',
        'length' => 36,
        'not null' => TRUE,
        'default' => '',
      ],
      'usage_count' => [
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
    ],
    'primary key' => ['asset_uuid'],
  ];

  $schema = Database::getConnection()->schema();
  $schema->createTable('acquia_dam_integration_link_aggregate', $config);

  _acquia_dam_populate_integration_link_aggregate_table();
}

/**
 * Checks if tracking table is not empty then populate aggregate table.
 *
 * @throws \Exception
 */
function _acquia_dam_populate_integration_link_aggregate_table() {
  $database = \Drupal::database();

  $count_query = $database
    ->select('acquia_dam_integration_link_tracking')
    ->countQuery();

  // If tracking table is empty, do nothing.
  if (!$count_query->execute()->fetchField()) {
    return;
  }

  $select = \Drupal::database()->select('acquia_dam_integration_link_tracking', 't');
  $select->addExpression('COUNT(t.asset_uuid)');
  $select = $select
    ->fields('t', ['asset_uuid'])
    ->groupBy('t.asset_uuid');

  $insert = $database
    ->insert('acquia_dam_integration_link_aggregate')
    ->fields(['asset_uuid', 'usage_count']);

  foreach ($select->execute()->fetchAll() as $result) {
    $insert->values([
      'asset_uuid' => $result->asset_uuid,
      'usage_count' => $result->expression,
    ]);
  }

  $insert->execute();
}

/**
 * Imports configuration changes.
 *
 * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
 * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
 */
function _acquia_dam_add_dam_content_views() {
  $configuration_map = [
    'views.view.dam_content_overview',
    'views.view.acquia_dam_links',
  ];

  $source = new FileStorage(__DIR__ . '/config/install');
  $entity_storage = \Drupal::entityTypeManager()->getStorage('view');

  foreach ($configuration_map as $config) {
    $entity = $entity_storage->createFromStorageRecord($source->read($config));
    $entity->save();
  }
}

/**
 * Updates asset library configuration.
 */
function acquia_dam_update_9004() {
  $configs = [
    'acquia_dam_asset_library' => 'views.view.acquia_dam_asset_library',
    'dam_content_overview' => 'views.view.dam_content_overview',
  ];
  $source = new FileStorage(__DIR__ . '/config/install');
  $entity_storage = \Drupal::entityTypeManager()->getStorage('view');
  $view_configs = $entity_storage->loadMultiple(array_keys($configs));
  foreach ($view_configs as $view_config) {
    $entity = $entity_storage
      ->updateFromStorageRecord(
        $view_config,
        $source->read($configs[$view_config->id()])
      );
    $entity->save();
  }

  $field_storage_definition = MediaExpiryDateField::getStorageDefinition('media');
  $update_manager = \Drupal::entityDefinitionUpdateManager();
  $update_manager->installFieldStorageDefinition(
    MediaExpiryDateField::EXPIRY_DATE_FIELD_NAME,
    'media',
    'acquia_dam',
    $field_storage_definition
  );
}

/**
 * Install field storage for image alt text field.
 */
function acquia_dam_update_9005() {
  $field_storage_definition = ImageAltTextField::getStorageDefinition('media');
  $update_manager = \Drupal::entityDefinitionUpdateManager();
  $update_manager->installFieldStorageDefinition(
    ImageAltTextField::IMAGE_ALT_TEXT_FIELD_NAME,
    'media',
    'acquia_dam',
    $field_storage_definition
  );
}

/**
 * Uninstalls the acquia_dam_embeds field from the media entity.
 */
function acquia_dam_update_9006() {
  $entity_definition_update = \Drupal::entityDefinitionUpdateManager();
  if ($storage_definition = $entity_definition_update->getFieldStorageDefinition('acquia_dam_embeds', 'media')) {
    $entity_definition_update->uninstallFieldStorageDefinition($storage_definition);
  }
}

/**
 * Add the external_id column to the acquia_dam_asset media field.
 */
function acquia_dam_update_9007() {
  $processed_fields = [];
  $columns_to_add = ['external_id'];
  $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  $asset_field_definition = $field_type_manager->getDefinition('acquia_dam_asset');

  /** @var \Drupal\acquia_dam\Plugin\Field\FieldType\AssetItem $asset_item_class */
  $asset_item_class = $asset_field_definition['class'];

  $schema = \Drupal::database()->schema();
  $entity_type_manager = \Drupal::entityTypeManager();
  $entity_field_manager = \Drupal::service('entity_field.manager');

  // We can't use $entity_field_manager->getFieldMapByFieldType()
  // since it won't display the fields that are added via the
  // hook_entity_field_storage_info().
  $entity_field_map = [
    'media' => [
      MediaSourceField::SOURCE_FIELD_NAME => [
        'type' => "acquia_dam_asset",
        'bundles' => [
          'acquia_dam_documents_asset' => 'acquia_dam_documents_asset',
          'acquia_dam_image_asset' => 'acquia_dam_image_asset',
          'acquia_dam_pdf_asset' => 'acquia_dam_pdf_asset',
          'acquia_dam_spinset_asset' => 'acquia_dam_spinset_asset',
          'acquia_dam_video_asset' => 'acquia_dam_video_asset',
        ],
      ],
    ],
  ];
  // The key-value collection for tracking installed storage schema.
  $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
  $entity_definitions_installed = \Drupal::keyValue('entity.definitions.installed');

  foreach ($entity_field_map as $entity_type_id => $field_map) {
    $entity_storage = $entity_type_manager->getStorage($entity_type_id);
    // Only SQL storage based entities are supported / throw known exception.
    if (!($entity_storage instanceof SqlContentEntityStorage)) {
      continue;
    }

    $entity_type = $entity_type_manager->getDefinition($entity_type_id);
    $field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
    /** @var Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
    $table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
    // Only need field storage definitions of asset fields.
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition */
    foreach (array_intersect_key($field_storage_definitions, $field_map) as $field_storage_definition) {
      $field_name = $field_storage_definition->getName();
      try {
        $table = $table_mapping->getFieldTableName($field_name);
      }
      catch (SqlContentEntityStorageException $e) {
        // If there is no table or column, there's little we can do.
        continue;
      }

      // Get the revision table.
      if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
        $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition);
      }
      elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
        $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
      }

      // Load the installed field schema so that it can be updated.
      $schema_key = "$entity_type_id.field_schema_data.$field_name";
      $field_schema_data = $entity_storage_schema_sql->get($schema_key);

      $processed_fields[] = [$entity_type_id, $field_name];
      // Loop over each new column and add it as a schema column change.
      foreach ($columns_to_add as $column_id) {
        $column = $table_mapping->getFieldColumnName($field_storage_definition, $column_id);
        // Add `initial_from_field` to the new spec, as this will copy over
        // the entire data.
        $field_schema = $asset_item_class::schema($field_storage_definition);
        $spec = $field_schema['columns'][$column_id];
        // Add the new column.
        $schema->addField($table, $column, $spec);
        if ($revision_table) {
          $schema->addField($revision_table, $column, $spec);
        }

        // Add the new column to the installed field schema.
        if ($field_schema_data) {
          $field_schema_data[$table]['fields'][$column] = $field_schema['columns'][$column_id];
          $field_schema_data[$table]['fields'][$column]['not null'] = FALSE;
          if ($revision_table) {
            $field_schema_data[$revision_table]['fields'][$column] = $field_schema['columns'][$column_id];
            $field_schema_data[$revision_table]['fields'][$column]['not null'] = FALSE;
          }
        }
      }

      // Save changes to the installed field schema.
      if ($field_schema_data) {
        $entity_storage_schema_sql->set($schema_key, $field_schema_data);
      }

      $key = "$entity_type_id.field_storage_definitions";
      if ($definitions = $entity_definitions_installed->get($key)) {
        $definitions[$field_name] = $field_storage_definition;
        $entity_definitions_installed->set($key, $definitions);
      }
    }
  }
}

/**
 * Add the 2 new managed_file/managed_image fields to the media entity.
 *
 * Note: This update has moved to acquia_dam_update_9009.
 */
function acquia_dam_update_9008() {

}

/**
 * Add the 2 new managed_file/managed_image fields to the media entity.
 *
 * If 9008 was run, this will fix the existing definitions.
 */
function acquia_dam_update_9009() {
  $entity_type_id = 'media';
  $entity_update_manager = \Drupal::entityDefinitionUpdateManager();
  $field_name_list = [];
  $field_definitions = [
    ManagedFileField::class => ManagedFileField::MANAGED_FILE_FIELD_NAME,
    ManagedImageField::class => ManagedImageField::MANAGED_IMAGE_FIELD_NAME,
  ];

  foreach ($field_definitions as $field_class => $field_name) {
    // Bail out if there's nothing to do here.
    if ($entity_update_manager->getFieldStorageDefinition($field_name, $entity_type_id) !== NULL) {
      $field_name_list[] = $field_name;
      continue;
    }

    $entity_update_manager->installFieldStorageDefinition(
      $field_name,
      $entity_type_id,
      'acquia_dam',
      $field_class::getStorageDefinition($entity_type_id)
    );

  }

  if (count($field_name_list) > 0) {
    return t('The following fields were already present on the Media entity type: %field_name_list', [
      '%field_name_list' => implode(', ', $field_name_list),
    ]);
  }
}

/**
 * Update the directory name structure used for the on-site stored asset files.
 */
function acquia_dam_update_9011() {
  $config = \Drupal::configFactory()->getEditable('acquia_dam.settings');
  $config->set('asset_file_directory_path', 'dam/[media:acquia_dam_asset_id:external_id]');
  $config->save(TRUE);
}

/**
 * DB update hook #9010.
 *
 * Updates existing `media_library` view mode definitions to use the `asset_id`
 * field with the `remotely_referenced_thumbnail_image` embed style instead the
 * locally stored thumbnails.
 */
function acquia_dam_update_9010() {
  $dam_media_types = array_filter(\Drupal::entityTypeManager()->getStorage('media_type')->loadMultiple(), static function (MediaTypeInterface $media_type) {
    return $media_type->getSource() instanceof Asset;
  });

  foreach ($dam_media_types as $media_type) {
    $config = \Drupal::configFactory()->getEditable('core.entity_view_display.media.' . $media_type->id() . '.media_library');

    // Interfere only when necessary to reserve any customization
    // administrators might have made.
    if ($config->get('content.thumbnail.type') !== 'acquia_dam_thumbnail') {
      continue;
    }

    // A field might have any extra information (eg. third party settings) we
    // cannot prepare for. Thus handling the entire value set as a complete
    // block to preserve as much value as possible, overwrite only the minimum.
    $field_attributes = $config->get('content.thumbnail');
    $field_attributes['type'] = 'acquia_dam_embed_code';
    $field_attributes['settings']['embed_style'] = 'remotely_referenced_thumbnail_image';
    $field_attributes['settings']['thumbnail_width'] = (int) preg_replace('/^(\d+)px$/i', '$1', $config->get('content.thumbnail.settings.thumbnail_size'));
    unset($field_attributes['settings']['thumbnail_size']);

    // First set the new field with all the necessary information copied over.
    $config->clear('hidden.acquia_dam_asset_id');
    $config->set('content.acquia_dam_asset_id', $field_attributes);

    // Then delete the old field.
    $config->clear('content.thumbnail');
    $config->set('hidden.thumbnail', TRUE);

    // Finally save the config object.
    $config->save(TRUE);
  }
}

/**
 * Add Audio and Generic media types.
 */
function acquia_dam_update_9012() {
  $source = new FileStorage(__DIR__ . '/config/install');
  // Update Existing views.
  $update_views = [
    'acquia_dam_asset_library',
    'dam_content_overview',
    'acquia_dam_links',
  ];

  // Update existing configurations.
  $entity_storage = \Drupal::entityTypeManager()->getStorage('view');
  $configs_to_update = $entity_storage->loadMultiple($update_views);
  foreach ($configs_to_update as $config) {
    $entity = $entity_storage->updateFromStorageRecord($config, $source->read('views.view.' . $config->id()));
    $entity->save();
  }

  $config_to_add = [
    'media_type' => [
      'media.type.acquia_dam_audio_asset',
      'media.type.acquia_dam_generic_asset',
    ],
    'entity_view_display' => [
      'core.entity_view_display.media.acquia_dam_audio_asset.default',
      'core.entity_view_display.media.acquia_dam_audio_asset.media_library',
      'core.entity_view_display.media.acquia_dam_generic_asset.default',
      'core.entity_view_display.media.acquia_dam_generic_asset.media_library',
    ],
  ];
  foreach ($config_to_add as $config_type => $configs) {
    $entity_storage = \Drupal::entityTypeManager()->getStorage($config_type);

    // Add new configurations.
    foreach ($configs as $config) {
      $entity = $entity_storage->createFromStorageRecord($source->read($config));
      $entity->save();
    }
  }

  // Create the Check for asset update action.
  // Define the action.
  $action = [
    'id' => 'asset_update_check_action',
    'label' => 'Check for asset update',
    'type' => 'system',
    'plugin' => 'asset_update_check_action',
    'config' => [],
  ];

  // Check if the action already exists.
  if (!\Drupal\system\Entity\Action::load($action['id'])) {
    // Create the action.
    $action_entity = \Drupal\system\Entity\Action::create($action);
    $action_entity->save();
  }
}

/**
 * DB update hook #9013.
 *
 * Issue #3477945: Update the existing media types with new configurations.
 * Update the view with new configurations.
 * Create the Check for asset update action.
 */
function acquia_dam_update_9013() {
  // Issue #3494927: Update the existing media types with new configurations.
  // Do nothing.
}

/**
 * Grant 'authorize with acquia dam' permission to authenticated users.
 */
function acquia_dam_update_9014() {
  $authenticated_role = \Drupal::entityTypeManager()
    ->getStorage('user_role')
    ->load('authenticated');

  if ($authenticated_role) {
    $authenticated_role->grantPermission('authorize with acquia dam');
    $authenticated_role->save();
    return t('The "authorize with acquia dam" permission has been granted to authenticated users.');
  }
  else {
    return t('The authenticated user role could not be found. Permission not granted.');
  }
}

/**
 * Rebuild container for acquia_dam.media_library_field_widget_opener changes.
 */
function acquia_dam_update_9015() {
  \Drupal::getContainer()->get('kernel')->invalidateContainer();
}

/**
 * Update DAM view access permissions.
 */
function acquia_dam_update_9016() {
  $views = [
    'acquia_dam_asset_library',
    'dam_content_overview',
    'acquia_dam_links',
  ];
  foreach ($views as $view_id) {
    $view = View::load($view_id);

    if ($view) {
      $display = $view->get('display');

      // Force change of permissions for DAM admin views.
      $access = [
        'type' => 'perm',
        'options' => [
          'perm' => 'access media overview',
        ],
      ];

      $display['default']['display_options']['access'] = $access;
      $view->set('display', $display);
      $view->save();

      $msg = "Updated '$view_id' view to use 'view media overview' permission.";
      \Drupal::logger('acquia_dam')->notice($msg);
    }
  }
}

/**
 * Ensure existing domain storage is stripped of the protocol.
 */
function acquia_dam_update_9017() {
  $config = \Drupal::configFactory()->getEditable('acquia_dam.settings');
  $domain = $config->get('domain');
  if ($domain && (str_starts_with($domain, 'http://') || str_starts_with($domain, 'https://'))) {
    $parsed_url = parse_url($domain);
    if ($parsed_url && isset($parsed_url['host'])) {
      $config->set('domain', $parsed_url['host']);
      $config->save(TRUE);
      return t('The Acquia DAM domain has been updated to remove the protocol.');
    }
  }
}

/**
 * Create Archive media type for existing DAM installations.
 */
function acquia_dam_update_9018() {
  // Clear cached definitions to ensure the new acquia_dam_asset:archive
  // plugin is discovered before attempting to create the media type.
  \Drupal::service('plugin.manager.field.field_type')->clearCachedDefinitions();
  \Drupal::service('typed_data_manager')->clearCachedDefinitions();

  // Create the Archive media type and its view displays.
  $configs_to_create = [
    'media_type' => [
      'media.type.acquia_dam_archive_asset',
    ],
    'entity_view_display' => [
      'core.entity_view_display.media.acquia_dam_archive_asset.default',
      'core.entity_view_display.media.acquia_dam_archive_asset.media_library',
    ],
  ];

  $source = new FileStorage(__DIR__ . '/config/install');

  foreach ($configs_to_create as $config_type => $configs) {
    $entity_storage = \Drupal::entityTypeManager()->getStorage($config_type);

    foreach ($configs as $config_name) {
      try {
        // Check if config file exists
        if ($source->exists($config_name)) {
          $entity = $entity_storage->createFromStorageRecord($source->read($config_name));
          $entity->save();
        }
        else {
          \Drupal::logger('acquia_dam')->warning('Configuration file @config not found during Archive media type creation.', [
            '@config' => $config_name,
          ]);
        }
      }
      catch (\Exception $e) {
        \Drupal::logger('acquia_dam')->error('Failed to create @config: @error', [
          '@config' => $config_name,
          '@error' => $e->getMessage(),
        ]);
      }
    }
  }

  // For mismatch entities field report.
  $entity_type = \Drupal::entityTypeManager()->getDefinition('media');
  $update_manager = \Drupal::service('entity.definition_update_manager');
  $update_manager->installEntityType($entity_type);
}

/**
 * Register Acquia DAM bundle fields.
 */
function acquia_dam_update_9019() {
  try {
    \Drupal::service('acquia_dam.bundle_field_map')->registerBundleFields();
  }
  catch (\Exception $e) {
    \Drupal::logger('acquia_dam')->error('Failed to register bundle fields: @error', [
      '@error' => $e->getMessage(),
    ]);
  }
}

/**
 * Add default uri_scheme configuration for existing Acquia DAM media types.
 *
 * This update ensures that existing media types have the uri_scheme setting
 * added to their source configuration if it doesn't already exist. Defaults
 * to the system's default file scheme or 'public' for backward compatibility.
 */
function acquia_dam_update_9020() {
  $dam_media_types = \Drupal::service('acquia_dam.asset_updater')->getDamMediaTypes();
  $file_system_uri_scheme = \Drupal::service('config.factory')->get('system.file')->get('default_scheme') ?: 'public';

  /** @var \Drupal\media\MediaTypeInterface[] $media_types */
  $media_types = \Drupal::entityTypeManager()->getStorage('media_type')->loadMultiple($dam_media_types);
  foreach ($media_types as $media_type) {
    // Get current source configuration.
    $source_configuration = $media_type->get('source_configuration');
    // Only add uri_scheme if it doesn't already exist.
    if (empty($source_configuration['uri_scheme'])) {
      // Default to system's default file scheme or
      // 'public' for backward compatibility.
      $source_configuration['uri_scheme'] = $file_system_uri_scheme;

      // Update the configuration.
      $media_type->set('source_configuration', $source_configuration);
      $media_type->save();

      \Drupal::logger('acquia_dam')
        ->info('Added default uri_scheme (@scheme) to media type: @type', [
          '@scheme' => $source_configuration['uri_scheme'],
          '@type' => $media_type->id(),
        ]);
    }
  }
}

/**
 * Update acquia_dam_expiry_date field to use BIGINT for Y2038 compatibility.
 *
 * This update ensures that existing acquia_dam_expiry_date fields in the media
 * entity are updated to use a BIGINT-compatible integer type, allowing them to
 * store expiry dates beyond January 19, 2038. The update alters the database
 * schema for both the field and its revision table, and then flushes all
 * caches to ensure the changes take effect.
 */
function acquia_dam_update_9021() {
  \Drupal::service('acquia_dam.y2038_compatibility')->updateExpiryDateFieldToBigint();

  \Drupal::entityTypeManager()->clearCachedDefinitions();
  \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

  return t('Updated acquia_dam_expiry_date fields to BIGINT-compatible integer to handle dates beyond 2038.');
}

/**
 * Update timestamp fields mapped to DAM date fields to use BIGINT.
 *
 * This update iterates through all media types that are mapped to
 * DAM media types and ensures that any timestamp fields mapped to date fields
 * are updated to use BIGINT for Y2038 compatibility.
 */
function acquia_dam_update_9022() {
  $entity_type_manager = \Drupal::entityTypeManager();
  $dam_media_types = \Drupal::service('acquia_dam.asset_updater')->getDamMediaTypes();

  /** @var \Drupal\media\MediaTypeInterface[] $media_types */
  $media_types = $entity_type_manager->getStorage('media_type')->loadMultiple($dam_media_types);

  $y2038_service = \Drupal::service('acquia_dam.y2038_compatibility');
  $total_updated = 0;

  foreach ($media_types as $media_type) {
    $field_names = $y2038_service->findFieldsNeedingBigintConversion($media_type, FALSE);
    // Use service with $show_message = FALSE to avoid UI messages during update.
    $updated_count = $y2038_service->ensureBigintForMappedDateFields($media_type, $field_names, FALSE);
    $total_updated += $updated_count;
  }

  if ($total_updated > 0) {
    return t('Updated @count timestamp field(s) mapped to DAM date fields to BIGINT for Y2038 compatibility.', [
      '@count' => $total_updated,
    ]);
  }

  return t('No timestamp fields required updates.');
}
