<?php

/**
 * @file
 * Install, update and uninstall functions for the farmOS installation profile.
 */

use Drupal\Component\Serialization\Json;

/**
 * Implements hook_install_tasks().
 */
function farm_install_tasks(&$install_state) {

  // Add tasks for configuring farmOS and enabling modules.
  $tasks = [
    'farm_install_config' => [
      'type' => 'normal',
    ],
    '\Drupal\farm\Form\FarmModulesForm' => [
      'display_name' => t('Install modules'),
      'type' => 'form',
    ],
    'farm_install_modules' => [
      'type' => 'batch',
    ],
  ];
  return $tasks;
}

/**
 * Implements hook_install_tasks_alter().
 */
function farm_install_tasks_alter(&$tasks, $install_state) {

  // Override install task display names to replace "site" with "farmOS".
  $alter_display_names = [
    'install_profile_modules' => t('Install farmOS'),
    'install_configure_form' => t('Configure farmOS'),
  ];
  foreach ($alter_display_names as $task => $display_name) {
    if (!empty($tasks[$task]['display_name'])) {
      $tasks[$task]['display_name'] = $display_name;
    }
  }
}

/**
 * Install default farmOS configuration.
 */
function farm_install_config() {

  // Use private file system by default.
  \Drupal::configFactory()->getEditable('system.file')->set('default_scheme', 'private')->save();

  // Only allow admins to register new users.
  \Drupal::configFactory()->getEditable('user.settings')->set('register', 'admin_only')->save();
}

/**
 * Installs farmOS modules via a batch process.
 *
 * @param array $install_state
 *   An array of information about the current installation state.
 *
 * @return array
 *   The batch definition.
 */
function farm_install_modules(array &$install_state) {

  // Load the list of farmOS core modules.
  $all = farm_modules();

  // Load the list of modules that should be installed.
  // If provided, use the modules defined in farm.modules profile argument.
  // We assume this is an array of module machine names, unless it is simply a
  // string, which is interpreted as a shortcut for installing a set of modules.
  // Available shortcuts are:
  // - "all" (installs all modules)
  // - "default" (installs default and base modules)
  // - "base" (installs base modules only)
  if (!empty($install_state['forms']['farm']['modules'])) {
    $modules_arg = $install_state['forms']['farm']['modules'];
    $all = farm_modules();
    if ($modules_arg === 'all') {
      $modules = array_merge(array_keys($all['base']), array_keys($all['default']), array_keys($all['optional']));
    }
    elseif ($modules_arg === 'default') {
      $modules = array_merge(array_keys($all['base']), array_keys($all['default']));
    }
    elseif ($modules_arg === 'base') {
      $modules = array_keys($all['base']);
    }
    else {
      $modules = Json::decode($modules_arg);
      if (!is_array($modules)) {
        $modules = [];
      }
    }
  }

  // Use the state set by the \Drupal\farm\Form\FarmModulesForm submit method.
  // Merge base modules into it.
  else {
    $modules = \Drupal::state()->get('farm.install_modules') ?: [];
    $modules = array_merge(array_keys($all['base']), $modules);
  }

  // If this is running in the context of a functional test, do not install any
  // additional modules. This is a temporary hack.
  // @see Drupal\Tests\farm_test\Functional\FarmBrowserTestBase::setUp()
  // @todo https://www.drupal.org/project/farm/issues/3183739
  if (!empty($GLOBALS['farm_test'])) {
    $modules = [];
  }

  // Load a list of all available modules, so that we can display their names.
  $module_handler = \Drupal::service('module_handler');

  // Assemble the batch operation for installing modules.
  $operations = [];
  foreach ($modules as $module) {
    $operations[] = [
      '_farm_install_module_batch',
      [
        $module,
        $module_handler->getName($module),
      ],
    ];
  }
  $batch = [
    'operations' => $operations,
    'title' => t('Installing @drupal modules', ['@drupal' => drupal_install_profile_distribution_name()]),
    'error_message' => t('The installation has encountered an error.'),
  ];
  return $batch;
}

/**
 * Implements callback_batch_operation().
 *
 * Performs batch installation of farmOS modules.
 */
function _farm_install_module_batch($module, $module_name, &$context) {
  \Drupal::service('module_installer')->install([$module], TRUE);
  $context['results'][] = $module;
  $context['message'] = t('Installed %module module.', ['%module' => $module_name]);
}
