<?php

/**
 * @file
 * File for the Site Studio Installation Code.
 */

use Drupal\acquia_cms_common\Facade\ConfigHandlerFacade;
use Drupal\acquia_cms_site_studio\Facade\CohesionFacade;
use Drupal\acquia_cms_site_studio\Form\AcquiaCmsSiteStudioSiteConfigureForm;
use Drupal\acquia_cms_site_studio\Helper\SiteStudioPermissionHelper;
use Drupal\cohesion\Controller\AdministrationController;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\editor\EditorInterface;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;

/**
 * Extends drupal core site installer form to add SiteStudio config form.
 */
function acquia_cms_site_studio_form_install_configure_form_alter(&$form, FormStateInterface $form_state) {
  $acquiaSiteStudioForm = \Drupal::classResolver(AcquiaCmsSiteStudioSiteConfigureForm::class);
  $form = $acquiaSiteStudioForm->buildForm($form, $form_state);
  $form['#submit'][] = [$acquiaSiteStudioForm, 'submitForm'];
}

/**
 * Imports all Cohesion elements.
 */
function _acquia_cms_site_studio_install_initialize(): array {
  // Build and run the batch job for the initial import of Cohesion elements and
  // assets.
  // @todo When Cohesion provides a service to generate this batch job, use
  // that instead of calling an internal method of an internal controller, since
  // this may break at any time due to internal refactoring done by Cohesion.
  $batch = AdministrationController::batchAction(TRUE);
  if (isset($batch['error'])) {
    Drupal::messenger()->addError($batch['error']);
    return [];
  }
  return $batch;
}

/**
 * Imports the Cohesion UI kit that ships with this profile.
 *
 * @return array
 *   Batch for rebuild operation.
 *
 * @throws Exception
 */
function _acquia_cms_site_studio_import_ui_kit(): array {
  // During testing, we don't import the UI kit, because it takes forever.
  // Instead, we swap in a pre-built directory of Cohesion templates and assets.
  if (getenv('COHESION_ARTIFACT')) {
    return [];
  }
  /** @var \Drupal\acquia_cms_site_studio\Facade\CohesionFacade $facade */
  $facade = Drupal::classResolver(CohesionFacade::class);
  $facade->importSiteStudioPackages();
  return [];
}

/**
 * Update cohesion.settings config.
 */
function _acquia_cms_site_studio_update_settings() {
  $config = \Drupal::service('config.factory')->getEditable('cohesion.settings');
  $config->set('image_browser', [
    'config' => [
      'type' => 'imce_imagebrowser',
      'dx8_entity_browser' => 'media_browser',
      'cohesion_media_lib_types' => ['image'],
      'dx8_imce_stream_wrapper' => 'public',
    ],
    'content' => [
      'type' => 'medialib_imagebrowser',
      'dx8_entity_browser' => 'media_browser',
      'cohesion_media_lib_types' => ['image'],
    ],
  ]);
  $config->set('use_dx8', 'enable');
  $config->set('sidebar_view_style', 'titles');
  $config->save();
}

/**
 * Imports all Cohesion elements immediately in a batch process.
 *
 * @throws Exception
 */
function _acquia_cms_site_studio_init() {
  // Instead of returning the batch array, we are just executing the batch here.
  $batch = _acquia_cms_site_studio_install_initialize();
  _acquia_cms_site_studio_import_ui_kit();
  _acquia_cms_site_studio_update_settings();
  batch_set($batch);
}

/**
 * Implements hook_form_alter().
 */
function acquia_cms_site_studio_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  // Trigger site studio config import and rebuild whenever user
  // try to save site studio account settings or the site studio core
  // form from tour dashboard page.
  $allowed_form_ids = [
    'cohesion_account_settings_form',
    'acquia_cms_site_studio_core_form',
    'acquia_cms_tour_installation_wizard',
  ];
  if (in_array($form_id, $allowed_form_ids)) {
    $config = Drupal::config('cohesion.settings');
    $cohesion_configured = $config->get('api_key') && $config->get('organization_key');
    // We should add submit handler, only if cohesion keys are not already set.
    if (!$cohesion_configured) {
      $form['#submit'][] = '_acquia_cms_site_studio_init';
      // Here we are adding a separate submit handler to rebuild the cohesion
      // styles. Now the reason why we are doing this is because the rebuild is
      // expecting that all the entities of cohesion are in place but as the
      // cohesion is getting build for the first time and
      // install_acms_site_studio_initialize imports the
      // entities. So we cannot execute both the batch process in a single
      // function, Hence to achieve the synchronous behaviour we have separated
      // cohesion configuration import and cohesion style rebuild functionality
      // into separate submit handlers.
      // @see \Drupal\cohesion_website_settings\Controller\WebsiteSettingsController::batch
      // $form['#submit'][] = 'acquia_cms_site_studio_rebuild_styles';
    }
  }
}

/**
 * Implements hook_content_model_role_presave_alter().
 */
function acquia_cms_site_studio_content_model_role_presave_alter(RoleInterface &$role) {
  if (\Drupal::getContainer()->has('cohesion.utils') &&
    \Drupal::service('cohesion.utils')->usedx8Status() &&
    in_array($role->id(), [
      'content_administrator',
      'content_editor',
      'content_author',
      'site_builder',
    ])) {
    $permissions = SiteStudioPermissionHelper::getSiteStudioPermissionsByRole($role->id());
    foreach ($permissions as $permission) {
      $role->grantPermission($permission);
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 *
 * Adds the permissions to role.
 */
function acquia_cms_site_studio_cohesion_helper_category_insert(EntityInterface $entity) {
  _acquia_cms_site_studio_add_permissions($entity);
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 *
 * Adds the permissions to role.
 */
function acquia_cms_site_studio_cohesion_component_category_insert(EntityInterface $entity) {
  _acquia_cms_site_studio_add_permissions($entity);
}

/**
 * Helper function to add Site Studio component permissions to roles.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   Site Studio component entity.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function _acquia_cms_site_studio_add_permissions(EntityInterface $entity) {
  $roles = [
    'content_administrator',
    'content_author',
    'content_editor',
  ];
  foreach ($roles as $role) {
    $permissions = SiteStudioPermissionHelper::getDynamicPermissionsByRole($role);
    $permissionToProvide = "access " . $entity->id() . " " . $entity->bundle() . " group";
    if (in_array($permissionToProvide, $permissions)) {
      $roleObject = Role::load($role);
      if ($roleObject) {
        $roleObject->grantPermission($permissionToProvide);
        $roleObject->save();
      }
    }
  }
}

/**
 * Implements hook_modules_installed().
 */
function acquia_cms_site_studio_modules_installed($modules, $is_syncing) {
  if (!$is_syncing) {
    if (in_array('cohesion_style_guide', $modules)) {
      user_role_grant_permissions('developer', [
        'administer style_guide',
      ]);
      user_role_grant_permissions('site_builder', [
        'administer style_guide',
      ]);
    }
    if (in_array('node_revision_delete', $modules)) {
      $config_handler = \Drupal::classResolver(ConfigHandlerFacade::class);
      $config_handler->setModuleName('node_revision_delete');
      // Node revision default config settings.
      $default_settings = [
        'defaults' => [
          'amount' => [
            'status' => TRUE,
            'settings' => [
              'amount' => 50,
            ],
          ],
          'created' => [
            'status' => TRUE,
            'settings' => [
              'age' => 12,
            ],
          ],
          'drafts' => [
            'status' => TRUE,
            'settings' => [
              'age' => 12,
            ],
          ],
        ],
      ];
      // Set default node revision delete settings shipped by Acquia CMS.
      $config_handler->processConfigSettings($default_settings);
      if (\Drupal::service('module_handler')->moduleExists('acquia_cms_page')) {
        // Node revision third party settings for page content type.
        $third_party_settings = [
          'amount' => [
            'status' => TRUE,
            'settings' => [
              'amount' => 30,
            ],
          ],
          'created' => [
            'status' => FALSE,
            'settings' => [
              'age' => 0,
            ],
          ],
          'drafts' => [
            'status' => FALSE,
            'settings' => [
              'age' => 0,
            ],
          ],
          'drafts_only' => [
            'status' => FALSE,
            'settings' => [
              'age' => 0,
            ],
          ],
        ];
        // Set default node revision delete configuration for Page content type
        // and entity node_type.
        $config_handler->processThirdPartySettings([
          'entity_type' => 'node_type',
          'bundle' => 'page',
        ], $third_party_settings);
      }

    }
  }
}

/**
 * Implements hook_library_info_alter().
 */
function acquia_cms_site_studio_library_info_alter(array &$libraries, string $module): void {
  // Remove the default css provided by module: `collapsiblock` module.
  // It causes issue with site studio template.
  if ($module == "collapsiblock" && isset($libraries['core']['css'])) {
    unset($libraries['core']['css']);
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 *
 * The permission to developer role to use a newly added text format.
 *
 * @param \Drupal\editor\EditorInterface $editor
 *   The filter format entity.
 */
function acquia_cms_site_studio_editor_insert(EditorInterface $editor) {
  // If the filter format entity isn't syncing, then update it.
  // Otherwise, no action is needed.
  if (!$editor->isSyncing()) {
    // Add text format permission to a developer role.
    $role = \Drupal::entityTypeManager()->getStorage('user_role')->load('developer');
    $role->grantPermission('use text format ' . $editor->id())->save(TRUE);
  }
}
