<?php

namespace Drupal\straker_translate\Form;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\straker_translate\LanguageLocaleMapperInterface;
use Drupal\straker_translate\StrakerTranslate;
use Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface;
use Drupal\straker_translate\StrakerTranslateInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 *
 */
class StrakerTranslateContentTranslationForm extends StrakerTranslateConfigFormBase {

  /**
   * The language-locale mapper.
   *
   * @var \Drupal\straker_translate\LanguageLocaleMapperInterface
   */
  protected $languageLocaleMapper;

  /**
   * The Straker Translate configuration service.
   *
   * @var \Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface
   */
  protected $straker_translateConfiguration;

  /**
   * Constructs a \Drupal\straker_translate\Form\StrakerTranslateContentTranslationForm object.
   *
   * @param \Drupal\straker_translate\StrakerTranslateInterface $straker_translate
   * @param \Drupal\straker_translate\LanguageLocaleMapperInterface $language_locale_mapper
   *   The language-locale mapper.
   * @param \Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface $straker_translate_configuration
   *   The Straker Translate configuration 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.
   */
  public function __construct(StrakerTranslateInterface $straker_translate, LanguageLocaleMapperInterface $language_locale_mapper, StrakerTranslateConfigurationServiceInterface $straker_translate_configuration, ConfigFactoryInterface $config, UrlGeneratorInterface $url_generator = NULL, LinkGeneratorInterface $link_generator = NULL) {
    parent::__construct($straker_translate, $config, $url_generator, $link_generator);
    $this->languageLocaleMapper = $language_locale_mapper;
    $this->straker_translateConfiguration = $straker_translate_configuration;
  }

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

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'straker_translate.content_translation_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, array $build = NULL) {
    /** @var \Drupal\straker_translate\StrakerTranslateContentTranslationServiceInterface $translation_service */
    $translation_service = \Drupal::service('straker_translate.content_translation');

    $entity = $build['#entity'];
    $entity_type = $entity->getEntityTypeId();

    $document_id = $translation_service->getDocumentId($entity);
    $source_language = $translation_service->getSourceLocale($entity);
    $source_status = $translation_service->getSourceStatus($entity);
    $status_check_needed = ($source_status == StrakerTranslate::STATUS_EDITED) ? TRUE : FALSE;

    $form_state->set('entity', $entity);
    $overview = $build['content_translation_overview'];
    $form['#title'] = $this->t('Translations of @title', ['@title' => $entity->label()]);

    $form['languages'] = [
      '#type' => 'table',
      '#header' => $overview['#header'],
      '#rows' => [],
    ];

    $languages = \Drupal::languageManager()->getLanguages();

    foreach ($languages as $langcode => $language) {
      $locale = $this->languageLocaleMapper->getLocaleForLangcode($langcode);

      $option = array_shift($overview['#rows']);

      $configLanguage = ConfigurableLanguage::load($langcode);
      $enabled = $this->straker_translateConfiguration->isLanguageEnabled($configLanguage) && \Drupal::currentUser()->hasPermission('manage straker_translate translations');

      if ($source_language == $locale) {
        // Check-Progress button if the source upload status is PENDING.
        if ($enabled && (in_array($source_status, [StrakerTranslate::STATUS_READY, StrakerTranslate::STATUS_PROCESSING])) && !empty($document_id)) {
          $checkPath = '/admin/straker-translate/entity/check_upload/' . $document_id;
          $path = '/admin/straker-translate/batch/uploadSingle/' . $entity_type . '/' . $entity->id();
          $this->addOperationLink($entity, $option, 'Check Upload Status', $checkPath, $language);
          $this->addOperationLink($entity, $option, 'Upload', $path, $language);
        }
        // Upload button if the status is EDITED or non-existent.
        elseif ($enabled && (in_array($source_status, [StrakerTranslate::STATUS_EDITED, StrakerTranslate::STATUS_ERROR, StrakerTranslate::STATUS_UNTRACKED, StrakerTranslate::STATUS_ARCHIVED, StrakerTranslate::STATUS_DELETED, NULL]))) {
          $path = '/admin/straker-translate/batch/uploadSingle/' . $entity_type . '/' . $entity->id();
          $this->addOperationLink($entity, $option, 'Upload to Straker', $path, $language);
        }
        elseif ($enabled && ($source_status === StrakerTranslate::STATUS_CURRENT)) {
          // Allow to re-upload if the status is current.
          $path = '/admin/straker-translate/batch/uploadSingle/' . $entity_type . '/' . $entity->id();
          $this->addOperationLink($entity, $option, 'Re-Upload to Straker', $path, $language);
        }
      }
      if ($source_language !== $locale && $enabled) {
        // Buttons for the ENTITY TARGET LANGUAGE.
        $target_status = $translation_service->getTargetStatus($entity, $langcode);

        // Add-Targets button if languages haven't been added, or if target status is UNTRACKED.
        if (($source_status === StrakerTranslate::STATUS_CURRENT)
              && !empty($document_id)
              && (!isset($target_status) || $target_status === StrakerTranslate::STATUS_READY || $target_status === StrakerTranslate::STATUS_ERROR)
        ) {
          // Download button if translations are READY or CURRENT.
          $path = '/admin/straker-translate/entity/download/' . $document_id . '/' . $locale;
          $this->addOperationLink($entity, $option, 'Download completed translation', $path, $language, TRUE);
        }
        elseif ($target_status === StrakerTranslate::STATUS_CURRENT) {
          $path = '/admin/straker-translate/workbench/' . $document_id;
          $this->addOperationLink($entity, $option, 'View in Straker Workbench', $path, $language);
          $path = '/admin/straker-translate/entity/download/' . $document_id . '/' . $locale;
          $this->addOperationLink($entity, $option, 'Re-download completed translation', $path, $language);
        }
      }

      $form['languages']['#rows'][$langcode] = $option;
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_values = $form_state->getValues();
    $entity = $form_values['entity'];
    $selected_langcodes = $form_values['languages'];
    $locales = [];
    foreach ($selected_langcodes as $langcode => $selected) {
      if ($selected) {
        $locale = $this->languageLocaleMapper->getLocaleForLangcode($langcode);
        $locales[] = $locale;
      }
    }

  }

  /**
   *
   */
  protected function getOperationColumnId(ContentEntityInterface $entity, array $option) {
    $found = -1;
    foreach ($option as $index => $column) {
      if (is_array($column) && isset($column['data']) && isset($column['data']['#type']) && $column['data']['#type'] === 'operations') {
        $found = $index;
        break;
      }
    }
    return $found;
  }

  /**
   * Add an operation to the list of available operations for each language.
   */
  protected function addOperationLink(ContentEntityInterface $entity, array &$option, $name, $path, LanguageInterface $language, $first = FALSE) {
    $operation_col = $this->getOperationColumnId($entity, $option);
    $open_in_window = FALSE;

    if (!isset($option[$operation_col]['data']['#links'])) {
      $option[$operation_col]['data']['#links'] = [];
    }
    if (is_string($path)) {
      if (strpos($path, '/admin/straker-translate/batch/') === 0) {
        $path = str_replace('/admin/straker-translate/batch/', '', $path);
        [$action, $entity_type, $entity_id] = explode('/', $path);
        $url = Url::fromRoute('straker_translate.batch', [
          'action' => $action,
          'entity_type' => $entity_type,
          'entity_id' => $entity_id,
        ]);
      }
      elseif (strpos($path, '/admin/straker-translate/entity/check_upload/') === 0) {
        $doc_id = str_replace('/admin/straker-translate/entity/check_upload/', '', $path);
        $url = Url::fromRoute('straker_translate.entity.check_upload', ['doc_id' => $doc_id]);
      }
      elseif (strpos($path, '/admin/straker-translate/entity/check_target/') === 0) {
        $path = str_replace('/admin/straker-translate/entity/check_target/', '', $path);
        [$doc_id, $locale] = explode('/', $path);
        $url = Url::fromRoute('straker_translate.entity.check_target', [
          'doc_id' => $doc_id,
          'locale' => $locale,
        ]);
      }
      elseif (strpos($path, '/admin/straker-translate/entity/download/') === 0) {
        $path = str_replace('/admin/straker-translate/entity/download/', '', $path);
        [$doc_id, $locale] = explode('/', $path);
        $target_file_id = \Drupal::service('straker_translate.content_translation')->getTargetFileId($entity, $language->getId());
        $url = Url::fromRoute('straker_translate.entity.download', [
          'doc_id' => $doc_id,
          'file_id' => $target_file_id,
          'langcode' => $language->getId(),
        ]);
      }
      elseif (strpos($path, '/admin/straker-translate/workbench/') === 0) {
        $doc_id = str_replace('/admin/straker-translate/workbench/', '', $path);
        $url = Url::fromRoute('straker_translate.workbench', [
          'doc_id' => $doc_id,
        ]);
        $open_in_window = TRUE;
      }
      else {
        die("failed to get known operation in addOperationLink: $path");
      }
    }
    else {
      $url = $path;
    }

    if ($first) {
      $previous = $option[$operation_col]['data']['#links'];
      $option[$operation_col]['data']['#links'] = [];
      $option[$operation_col]['data']['#links'][strtolower($name)] = [
        'title' => $name,
        'url' => $url,
      ];
      $option[$operation_col]['data']['#links'] += $previous;
    }
    else {
      $option[$operation_col]['data']['#links'][strtolower($name)] = [
        'title' => $name,
        'url' => $url,
      ];
    }
    if ($open_in_window) {
      $option[$operation_col]['data']['#links'][strtolower($name)]['attributes']['target'] = '_blank';
    }
  }

  /**
   *
   */
  protected function removeOperationLink(ContentEntityInterface $entity, array &$option, $name) {
    $operation_col = $this->getOperationColumnId($entity, $option);

    unset($option[$operation_col]['data']['#links'][strtolower($name)]);
  }

}
