<?php

namespace Drupal\straker_translate\Form;

use Drupal\block\BlockRepositoryInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\straker_translate\StrakerTranslateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Configure Straker Translate.
 */
class StrakerTranslateSettingsTabPreferencesForm extends StrakerTranslateConfigFormBase {

  protected $lang_switcher_value = 0;
  protected $top_level_value = 0;
  protected $lang_switcher;
  protected $lang_switcher_region;
  protected $lang_regions;
  protected $lang_region_selected;
  protected $default_region = 'sidebar_first';


  /**
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a \Drupal\straker_translate\Form\StrakerTranslateConfigFormBase object.
   *
   * @param \Drupal\straker_translate\StrakerTranslateInterface $straker_translate
   *   The straker_translate service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
   *   The factory for configuration objects.
   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
   *   The url generator.
   * @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
   *   The link generator.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   */
  public function __construct(StrakerTranslateInterface $straker_translate, ConfigFactoryInterface $config, UrlGeneratorInterface $url_generator, LinkGeneratorInterface $link_generator, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($straker_translate, $config, $url_generator, $link_generator);
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('straker_translate'),
      $container->get('config.factory'),
      $container->get('url_generator'),
      $container->get('link_generator'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormID() {
    return 'straker_translate.settings_tab_preferences_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    /** @var \Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface $straker_translate_config */
    $straker_translate_config = \Drupal::service('straker_translate.configuration');

    $this->retrieveLanguageSwitcher();
    $this->retrieveAdminMenu();

    $form['prefs'] = [
      '#type' => 'details',
      '#title' => t('Preferences'),
    ];

    $form['prefs']['lang_switcher'] = [
      '#type' => 'checkbox',
      '#title' => 'Enable the default language switcher',
      '#default_value' => $this->lang_switcher_value,
    ];

    $form['prefs']['lang_switcher_select'] = [
      '#type' => 'select',
      '#description' => $this->t('The region where the switcher will be displayed') . '<br>' . $this->t('Note: The default language switcher block is only shown if at least two languages are enabled and language negotiation is set to <em>URL</em> or <em>Session</em>. Go to <a href=":url">%language_detection</a> to change this.',
          ['%language_detection' => $this->t('Language detection and selection'), ':url' => Url::fromRoute('language.negotiation')->toString()]),
      '#options' => $this->lang_regions,
      '#default_value' => $this->lang_region_selected == 'none' ? $this->default_region : $this->lang_region_selected,
      '#states' => [
        'visible' => [
          ':input[name="lang_switcher"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['prefs']['hide_top_level'] = [
      '#type' => 'checkbox',
      '#title' => t('Hide top-level menu item'),
      '#description' => t('When hidden, the module can still be accessed under <i>Configuration > Regional and language</i>. <p> Note: It will take a few seconds to save if this setting is changed.'),
      '#default_value' => $this->top_level_value,
    ];

    $form['prefs']['show_language_labels'] = [
      '#type' => 'checkbox',
      '#title' => t('Show language label on node pages'),
      '#description' => t("If checked, language labels will be displayed for nodes that have the 'language selection' field set to be visible."),
      '#default_value' => $straker_translate_config->getPreference('show_language_labels'),
    ];

    $form['prefs']['always_show_translate_tabs'] = [
      '#type' => 'checkbox',
      '#title' => t('Always show non-Straker translate tabs'),
      '#description' => t('If checked, edit-form tabs for both Content Translation and Entity Translation will not be hidden, even if the entity is managed by Straker.'),
      '#default_value' => $straker_translate_config->getPreference('always_show_translate_tabs'),
    ];

    $form['prefs']['allow_local_editing'] = [
      '#prefix' => '<div style="margin-left: 20px;">',
      '#suffix' => '</div>',
      '#type' => 'checkbox',
      '#title' => t('Allow local editing of Straker translations'),
      '#description' => t('If checked, local editing of translations managed by Straker Translate will be allowed. (Note: any changes made may be overwritten if the translation is downloaded from Straker Translate again.)'),
      '#default_value' => $straker_translate_config->getPreference('allow_local_editing'),
      '#states' => [
        'visible' => [
          ':input[name="always_show_translate_tabs"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $states = [
      'published' => t('Published'),
      'unpublished' => t('Unpublished'),
      'same-as-source' => t('Same as source content'),
    ];

    $form['prefs']['target_download_status'] = [
      '#type' => 'select',
      '#title' => t('Translations download publication status'),
      '#description' => t('Translations download publication status: specify which published status the translations downloads must be saved with.'),
      '#options' => $states,
      '#default_value' => $straker_translate_config->getPreference('target_download_status') ?: 'same-as-source',
    ];

    $form['prefs']['enable_download_source'] = [
      '#type' => 'checkbox',
      '#title' => t('Download source if content is missing'),
      '#description' => t('If some content is not shown, the original words will be.'),
      '#default_value' => $straker_translate_config->getPreference('enable_download_source') ?: FALSE,
    ];

    $form['prefs']['append_type_to_title'] = [
      '#type' => 'checkbox',
      '#title' => t('Append Entity Type to Verify Document Name'),
      '#description' => t('Enable to have content/entity type appended to the document title in Straker Verify.'),
      '#default_value' => $straker_translate_config->getPreference('append_type_to_title'),
    ];

    $form['prefs']['split_download_all'] = [
      '#type' => 'checkbox',
      '#title' => t('Use a different batch per locale when downloading all translations'),
      '#description' => t('Uses a different batch process per locale. This option can be used to prevent timeouts during download all translations.'),
      '#default_value' => $straker_translate_config->getPreference('split_download_all') ?: FALSE,
    ];

    $form['prefs']['actions']['#type'] = 'actions';
    $form['prefs']['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => t('Save'),
      '#button_type' => 'primary',
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    /** @var \Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface $straker_translate_config */
    $straker_translate_config = \Drupal::service('straker_translate.configuration');

    $form_values = $form_state->getValues();

    $this->saveAdminMenu($form_values);
    $this->saveLanguageSwitcherSettings($form_values);
    $this->saveShowLanguageFields($form_values);
    $this->saveAlwaysShowTranslateTabs($form_values);
    $straker_translate_config->setPreference('append_type_to_title', $form_values['append_type_to_title'] ? TRUE : FALSE);
    $straker_translate_config->setPreference('target_download_status', $form_values['target_download_status']);
    $straker_translate_config->setPreference('enable_download_source', $form_values['enable_download_source'] ? TRUE : FALSE);
    $straker_translate_config->setPreference('split_download_all', $form_values['split_download_all'] ? TRUE : FALSE);
    parent::submitForm($form, $form_state);
  }

  /**
   *
   */
  protected function retrieveLanguageSwitcher() {
    if (\Drupal::moduleHandler()->moduleExists('block')) {
      $theme_default = $this->config('system.theme')->get('default');
      $this->lang_regions = system_region_list($theme_default, BlockRepositoryInterface::REGIONS_VISIBLE);
      $ids = \Drupal::entityQuery('block')
        ->accessCheck(FALSE)
        ->condition('plugin', 'language_block:language_interface')
        ->condition('theme', $theme_default)
        ->execute();
      if ($ids) {
        // We just take the first language switcher.
        $this->lang_switcher = \Drupal::entityTypeManager()->getStorage('block')->load(reset($ids));
        $this->lang_switcher_value = $this->lang_switcher->status();
        $this->lang_region_selected = $this->lang_switcher->getRegion();
      }
      else {
        $this->lang_switcher_value = 0;
        $this->lang_region_selected = $this->default_region;
      }
    }
  }

  /**
   *
   */
  protected function saveLanguageSwitcherSettings($form_values) {
    // If the website doesn't have a language switcher yet, don't act on it.
    if ($this->lang_switcher) {
      $this->lang_switcher->setRegion($form_values['lang_switcher_select']);
      if ($form_values['lang_switcher']) {
        $this->lang_switcher->enable();
      }
      else {
        $this->lang_switcher->disable();
      }
      $this->lang_switcher->save();
    }
    else {
      // If the user selects the checkbox, and no language switcher exists yet, create one.
      if ($form_values['lang_switcher']) {
        $config = $this->config('system.theme');
        $theme_default = $config->get('default');
        $this->lang_switcher = \Drupal::entityTypeManager()->getStorage('block')->create(['plugin' => 'language_block:language_interface', 'theme' => $theme_default]);
        $this->lang_switcher->setRegion($form_values['lang_switcher_select']);
        $this->lang_switcher->enable();
        $this->lang_switcher->set('id', 'languageswitcher');
        $this->lang_switcher->save();
      }
    }
  }

  /**
   *
   */
  protected function retrieveAdminMenu() {
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
    $admin_menu = $menu_link_manager->getDefinition('straker_translate.dashboard');

    // Will be opposite from enabled value since we're hiding the menu item.
    if ($admin_menu['enabled']) {
      $this->top_level_value = 0;
    }
    else {
      $this->top_level_value = 1;
    }
  }

  /**
   *
   */
  protected function saveAdminMenu($form_values) {
    $updated_values = [];
    $should_reset_cache = FALSE;

    /** @var \Drupal\Core\Menu\MenuLinkManager $menu_link_manager */
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');

    // Only run if there's been a change to avoid clearing the cache if we don't have to.
    if ($this->top_level_value != $form_values['hide_top_level']) {
      if ($form_values['hide_top_level']) {
        $updated_values = [
          'enabled' => 0,
        ];
      }
      else {
        $updated_values = [
          'enabled' => 1,
        ];
      }

      $menu_link_manager->updateDefinition('straker_translate.dashboard', $updated_values);
      $ids = $menu_link_manager->getChildIds('straker_translate.dashboard');
      foreach ($ids as $child_link) {
        $menu_link_manager->updateDefinition($child_link, $updated_values);
      }
      if ($updated_values['enabled']) {
        $menu_link_manager->resetLink('straker_translate.dashboard');
      }
      $should_reset_cache = TRUE;
    }
    if ($should_reset_cache) {
      drupal_flush_all_caches();
    }
  }

  /**
   *
   */
  protected function saveAlwaysShowTranslateTabs($form_values) {
    $config = \Drupal::configFactory()->getEditable('straker_translate.settings');
    $config->set('preference.always_show_translate_tabs', $form_values['always_show_translate_tabs'] ? TRUE : FALSE);
    if ($form_values['always_show_translate_tabs']) {
      $config->set('preference.allow_local_editing', $form_values['allow_local_editing'] ? TRUE : FALSE);
    }
    else {
      $config->set('preference.allow_local_editing', FALSE);
    }
    $config->save();
  }

  /**
   *
   */
  protected function saveShowLanguageFields($form_values) {
    $config = \Drupal::configFactory()->getEditable('straker_translate.settings');
    // Only save if there's a change to the show_language_labels choice.
    if ($config->get('preference.show_language_labels') != $form_values['show_language_labels']) {
      $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('node');

      foreach ($bundles as $bundle_id => $bundle) {
        if ($bundle['translatable']) {
          $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', $bundle_id);
          $langcode = $field_definitions['langcode'];
          $display = $this->entityTypeManager->getStorage('entity_view_display')
            ->load('node.' . $bundle_id . '.default');

          if ($form_values['show_language_labels']) {
            $component_values = [
              'type' => 'language',
              'weight' => 0,
              'settings' => [],
              'third_party_settings' => [],
            // Can be above, inline, hidden, or visually_hidden (These are hard coded in core)
              'label' => 'above',
            ];
            $display->setComponent('langcode', $component_values);
          }
          else {
            $display->removeComponent('langcode');
          }
          $display->save();
        }
      }
    }
    $config->set('preference.show_language_labels', $form_values['show_language_labels'] ? TRUE : FALSE);
    $config->save();
  }

}
