<?php

namespace Drupal\straker_translate\Controller;

use Drupal\config_translation\ConfigEntityMapper;
use Drupal\config_translation\ConfigMapperManagerInterface;
use Drupal\config_translation\Controller\ConfigTranslationController;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\straker_translate\Exception\StrakerTranslateApiException;
use Drupal\straker_translate\Exception\StrakerTranslateDocumentAlreadyUploaded;
use Drupal\straker_translate\Exception\StrakerTranslateDocumentArchivedException;
use Drupal\straker_translate\Exception\StrakerTranslateDocumentLockedException;
use Drupal\straker_translate\Exception\StrakerTranslateDocumentNotFoundException;
use Drupal\straker_translate\Exception\StrakerTranslatePaymentRequiredException;
use Drupal\straker_translate\Exception\StrakerTranslateProcessedWordsLimitException;
use Drupal\straker_translate\LanguageLocaleMapperInterface;
use Drupal\straker_translate\StrakerTranslate;
use Drupal\straker_translate\StrakerTranslateConfigTranslationServiceInterface;
use Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;

/**
 *
 */
class StrakerTranslateConfigTranslationController extends ConfigTranslationController {

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

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

  /**
   * The Straker Translate config translation service.
   *
   * @var \Drupal\straker_translate\StrakerTranslateConfigTranslationServiceInterface
   */
  protected $translationService;

  /**
   * Constructs a StrakerTranslateConfigTranslationController.
   *
   * @param \Drupal\straker_translate\LanguageLocaleMapperInterface $language_locale_mapper
   *   The language-locale mapper.
   * @param \Drupal\straker_translate\StrakerTranslateConfigTranslationServiceInterface $translation_service
   *   The Straker Translate config translation service.
   * @param \Drupal\straker_translate\StrakerTranslateConfigurationServiceInterface $straker_translate_configuration
   *   The Straker Translate configuration service.
   * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
   *   The configuration mapper manager.
   * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
   *   The menu link access service.
   * @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
   *   The dynamic router service.
   * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
   *   The inbound path processor.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   */
  public function __construct(LanguageLocaleMapperInterface $language_locale_mapper, StrakerTranslateConfigTranslationServiceInterface $translation_service, StrakerTranslateConfigurationServiceInterface $straker_translate_configuration, ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager, RendererInterface $renderer) {
    parent::__construct($config_mapper_manager, $access_manager, $router, $path_processor, $account, $language_manager, $renderer);
    $this->languageLocaleMapper = $language_locale_mapper;
    $this->straker_translateConfiguration = $straker_translate_configuration;
    $this->translationService = $translation_service;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('straker_translate.language_locale_mapper'),
      $container->get('straker_translate.config_translation'),
      $container->get('straker_translate.configuration'),
      $container->get('plugin.manager.config_translation.mapper'),
      $container->get('access_manager'),
      $container->get('router'),
      $container->get('path_processor_manager'),
      $container->get('current_user'),
      $container->get('language_manager'),
      $container->get('renderer')
    );
  }

  /**
   *
   */
  public function itemPage(Request $request, RouteMatchInterface $route_match, $plugin_id) {
    $page = parent::itemPage($request, $route_match, $plugin_id);

    // If the user cannot manage translations, we don't add any actions.
    if (!\Drupal::currentUser()->hasPermission('manage straker_translate translations')) {
      return $page;
    }

    $entity = NULL;
    $entity_id = NULL;
    /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
    $mapper = $this->configMapperManager->createInstance($plugin_id);
    $mapper->populateFromRouteMatch($route_match);

    $languages = $this->languageManager->getLanguages();
    $languages = array_filter($languages, function (LanguageInterface $language) {
      $configLanguage = ConfigurableLanguage::load($language->getId());
      return $this->straker_translateConfiguration->isLanguageEnabled($configLanguage);
    });

    $original_langcode = $mapper->getLangcode();
    if (!isset($languages[$original_langcode])) {
      // If the language is not configured on the site, create a dummy language
      // object for this listing only to ensure the user gets useful info.
      $language_name = $this->languageManager->getLanguageName($original_langcode);
      $languages[$original_langcode] = new Language([
        'id' => $original_langcode,
        'name' => $language_name,
      ]);
    }
    if ($mapper instanceof ConfigEntityMapper) {
      /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
      $entity = $mapper->getEntity();
      $entity_id = $entity->id();
      $document_id = $this->translationService->getDocumentId($entity);
    }
    if ($entity_id === NULL) {
      $entity_id = $plugin_id;
      $config_document_id = $this->translationService->getConfigDocumentId($mapper);
    }

    foreach ($languages as $language) {
      $langcode = $language->getId();

      if ($langcode === $original_langcode) {
        $getSourceStatus = $entity
              ? $this->translationService->getSourceStatus($entity)
              : $this->translationService->getConfigSourceStatus($mapper);
        $upload_label = match ($getSourceStatus) {
          StrakerTranslate::STATUS_UNTRACKED => $this->t('Upload'),
          StrakerTranslate::STATUS_ERROR     => $this->t('Re-Upload'),
          default                   => NULL,
        };
        if ($upload_label) {
          // If we don't have a document id, we cannot do anything.
          $page['languages'][$langcode]['operations']['#links']['add'] = [
            'title' => $upload_label,
            'url' => Url::fromRoute('straker_translate.config.upload',
              [
                'entity_type' => $plugin_id,
                'entity_id' => $entity_id,
              ]),
          ];
        }
        if ($getSourceStatus == StrakerTranslate::STATUS_READY || $getSourceStatus == StrakerTranslate::STATUS_ERROR || $getSourceStatus == StrakerTranslate::STATUS_PROCESSING) {
          // If we have a document id, we can check the upload status.
          $page['languages'][$langcode]['operations']['#links']['check_upload'] = [
            'title' => $this->t('Check upload status'),
            'url' => Url::fromRoute('straker_translate.config.check_upload',
              [
                'entity_type' => $plugin_id,
                'entity_id' => $entity_id,
                'document_id' => $document_id,
              ]),
          ];
        }

      }
      if ($langcode !== $original_langcode) {
        if (isset($page['languages'][$langcode]['operations']['#links']['add'])) {
          // If we have a config entity and it has a document id, we want to show
          // the ability of requesting translations.
          if ($entity && $document_id) {
            $target_status = $this->translationService->getTargetStatus($entity, $langcode);
            $this->generateOperationsLinks($page, $plugin_id, $entity_id, $target_status, $mapper, $langcode);
          }
          // If it is a ConfigNamesMapper object, we need to call another method.
          elseif ($entity_id === $plugin_id && $config_document_id) {
            $target_status = $this->translationService->getConfigTargetStatus($mapper, $langcode);
            $this->generateOperationsLinks($page, $plugin_id, $entity_id, $target_status, $mapper, $langcode);
          }
        }
        if (isset($page['languages'][$langcode]['operations']['#links']['edit'])) {
          if ($entity && $document_id) {
            $target_status = $this->translationService->getTargetStatus($entity, $langcode);
            $this->generateOperationsLinks($page, $plugin_id, $entity_id, $target_status, $mapper, $langcode);
          }
          // If it is a ConfigNamesMapper object, we need to call another method.
          elseif ($entity_id === $plugin_id && $config_document_id) {
            $target_status = $this->translationService->getConfigTargetStatus($mapper, $langcode);
            $this->generateOperationsLinks($page, $plugin_id, $entity_id, $target_status, $mapper, $langcode);
          }
        }
      }
    }
    return $page;
  }

  /**
   *
   */
  public function upload($entity_type, $entity_id, Request $request) {
    if ($entity_type === $entity_id) {
      // It is not a config entity, but a config object.
      $definition = $this->configMapperManager->getDefinition($entity_type);
      $mappers = $this->configMapperManager->getMappers();
      try {
        if ($this->translationService->uploadConfig($entity_type)) {
          $this->messenger()->addStatus($this->t('%label uploaded successfully', ['%label' => $definition['title']]));
        }
        else {
          $this->messenger()->addError($this->t('%label upload failed. Please try again. Check the logs for more details',
            ['%label' => $definition['title']]));
        }
      }
      catch (StrakerTranslateDocumentNotFoundException $exception) {
        $this->messenger()->addError($this->t('Document %label was not found. Please upload again.',
          ['%label' => $mappers[$entity_type]->getTitle()]));
      }
      catch (StrakerTranslateDocumentArchivedException $exception) {
        $this->messenger()->addWarning($this->t('Document %label has been archived. Uploading again.',
          ['%label' => $mappers[$entity_type]->getTitle()]));
        return $this->upload($entity_type, $entity_id, $request);
      }
      catch (StrakerTranslateDocumentLockedException $exception) {
        $this->messenger()->addError($this->t('Document %label has a new version. The document id has been updated for all future interactions. Please try again.',
          ['%label' => $mappers[$entity_type]->getTitle()]));
      }
      catch (StrakerTranslatePaymentRequiredException $exception) {
        $this->messenger()->addError($this->t('Community has been disabled. Please contact support@straker_translate.com to re-enable your community.'));
      }
      catch (StrakerTranslateProcessedWordsLimitException $exception) {
        $this->messenger()->addError($this->t('Processed word limit exceeded. Please contact your local administrator or Straker Translate Client Success (<a href=":link">@mail</a>) for assistance.', [':link' => 'mailto:sales@straker_translate.com', '@mail' => 'sales@straker_translate.com']));
      }
      catch (StrakerTranslateApiException $e) {
        // Mark the document as failed.
        $this->messenger()->addError($this->t('%label upload failed. Please try again.',
          ['%label' => $mappers[$entity_type]->getTitle()]));
      }
      return $this->redirectToConfigTranslateOverview($entity_type);
    }
    // Check if it's a field.
    if (substr($entity_type, -7) == '_fields') {
      // Hack for fields, the entity is field config.
      $entity_type = 'field_config';
    }
    $entity = $this->entityTypeManager()->getStorage($entity_type)->load($entity_id);
    try {
      if ($this->translationService->uploadDocument($entity)) {
        $this->messenger()->addStatus($this->t('%label uploaded successfully', ['%label' => $entity->label()]));
      }
      else {
        $this->messenger()->addError($this->t('%label upload failed. Please try again. Check the logs for more details',
          ['%label' => $entity->label()]));
      }
    }
    catch (StrakerTranslateDocumentNotFoundException $exception) {
      $this->messenger()->addError($this->t('Document @entity_type %title was not found. Please upload again.', [
        '@entity_type' => $entity->getEntityTypeId(),
        '%title' => $entity->label(),
      ]));
    }
    catch (StrakerTranslateDocumentArchivedException $exception) {
      $this->messenger()->addWarning($this->t('Document @entity_type %title has been archived. Uploading again.', [
        '@entity_type' => $entity->getEntityTypeId(),
        '%title' => $entity->label(),
      ]));
      return $this->upload($entity_type, $entity_id, $request);
    }
    catch (StrakerTranslateDocumentLockedException $exception) {
      $this->messenger()->addError($this->t('Document @entity_type %title has a new version. The document id has been updated for all future interactions. Please try again.', ['@entity_type' => $entity->getEntityTypeId(), '%title' => $entity->label()]));
    }
    catch (StrakerTranslatePaymentRequiredException $exception) {
      $this->messenger()->addError($this->t('Community has been disabled. Please contact support@straker_translate.com to re-enable your community.'));
    }
    catch (StrakerTranslateProcessedWordsLimitException $exception) {
      $this->messenger()->addError($this->t('Processed word limit exceeded. Please contact your local administrator or Straker Translate Client Success (<a href=":link">@mail</a>) for assistance.', [':link' => 'mailto:sales@straker_translate.com', '@mail' => 'sales@straker_translate.com']));
    }
    catch (StrakerTranslateApiException $e) {
      $this->messenger()->addError($this->t('%label upload failed. Please try again.',
        ['%label' => $entity->label()]));
    }
    return $this->redirectToEntityTranslateOverview($entity_type, $entity_id);
  }

  /**
   *
   */
  public function update($entity_type, $entity_id, Request $request) {
    if ($entity_type === $entity_id) {
      // It is not a config entity, but a config object.
      $definition = $this->configMapperManager->getDefinition($entity_type);
      $mappers = $this->configMapperManager->getMappers();

      try {
        // Check if this is a re-upload request
        $is_reupload = $request->query->get('reupload') === '1';
        if ($this->translationService->uploadConfig($entity_type, $is_reupload)) {
          $message = $is_reupload ?
            $this->t('%label has been re-uploaded successfully.', ['%label' => $definition['title']]) :
            $this->t('%label has been updated.', ['%label' => $definition['title']]);
          $this->messenger()->addStatus($message);
        }
        else {
          $this->messenger()->addError($this->t('%label upload failed. Please try again. Check the logs for more details',
            ['%label' => $definition['title']]));
        }
      }
      catch (StrakerTranslateDocumentArchivedException $exception) {
        $this->messenger()->addWarning($this->t('Document %label has been archived. Uploading again.', [
          '%label' => $definition['title'],
        ]));
        return $this->upload($entity_type, $entity_id, $request);
      }
      catch (StrakerTranslateDocumentNotFoundException $exception) {
        $this->messenger()->addError($this->t('Document %label was not found. Please upload again.',
          ['%label' => $definition['title']]));
      }
      catch (StrakerTranslateDocumentLockedException $exception) {
        $this->messenger()->addError($this->t('Document %label has a new version. The document id has been updated for all future interactions. Please try again.',
          ['%label' => $definition['title']]));
      }
      catch (StrakerTranslatePaymentRequiredException $exception) {
        $this->messenger()->addError($this->t('Community has been disabled. Please contact support@straker_translate.com to re-enable your community.'));
      }
      catch (StrakerTranslateProcessedWordsLimitException $exception) {
        $this->messenger()->addError($this->t('Processed word limit exceeded. Please contact your local administrator or Straker Translate Client Success (<a href=":link">@mail</a>) for assistance.', [':link' => 'mailto:sales@straker_translate.com', '@mail' => 'sales@straker_translate.com']));
      }
      catch (StrakerTranslateApiException $e) {
        $this->messenger()->addError($this->t('%label update failed. Please try again.',
          ['%label' => $definition['title']]));
      }
      // Check for destination parameter for redirect
      $destination = $request->query->get('destination');
      if ($destination) {
        return new RedirectResponse($destination);
      }
      return $this->redirectToConfigTranslateOverview($entity_type);
    }
    // Check if it's a field.
    if (substr($entity_type, -7) == '_fields') {
      // Hack for fields, the entity is field config.
      $entity_type = 'field_config';
    }
    $entity = $this->entityTypeManager()->getStorage($entity_type)->load($entity_id);
    try {
      if ($this->translationService->uploadDocument($entity)) {
        $this->messenger()->addStatus($this->t('%label has been updated.', ['%label' => $entity->label()]));
      }
      else {
        $this->messenger()->addError($this->t('%label upload failed. Please try again. Check the logs for more details',
          ['%label' => $entity->label()]));
      }
    }
    catch (StrakerTranslateDocumentNotFoundException $exception) {
      $this->messenger()->addError($this->t('Document @entity_type %title was not found. Please upload again.', [
        '@entity_type' => $entity->getEntityTypeId(),
        '%title' => $entity->label(),
      ]));
    }
    catch (StrakerTranslateDocumentArchivedException $exception) {
      $this->messenger()->addWarning($this->t('Document @entity_type %title has been archived. Uploading again.', [
        '@entity_type' => $entity->getEntityTypeId(),
        '%title' => $entity->label(),
      ]));
      return $this->upload($entity_type, $entity_id, $request);
    }
    catch (StrakerTranslateDocumentLockedException $exception) {
      $this->messenger()->addError($this->t('Document @entity_type %title has a new version. The document id has been updated for all future interactions. Please try again.', ['@entity_type' => $entity->getEntityTypeId(), '%title' => $entity->label()]));
    }
    catch (StrakerTranslatePaymentRequiredException $exception) {
      $this->messenger()->addError($this->t('Community has been disabled. Please contact support@straker_translate.com to re-enable your community.'));
    }
    catch (StrakerTranslateProcessedWordsLimitException $exception) {
      $this->messenger()->addError($this->t('Processed word limit exceeded. Please contact your local administrator or Straker Translate Client Success (<a href=":link">@mail</a>) for assistance.', [':link' => 'mailto:sales@straker_translate.com', '@mail' => 'sales@straker_translate.com']));
    }
    catch (StrakerTranslateApiException $e) {
      $this->messenger()->addError($this->t('%label update failed. Please try again.',
        ['%label' => $entity->label()]));
    }
    // Check for destination parameter for redirect
    $destination = $request->query->get('destination');
    if ($destination) {
      return new RedirectResponse($destination);
    }
    return $this->redirectToEntityTranslateOverview($entity_type, $entity_id);
  }

  /**
   *
   */
  public function checkUpload($entity_type, $entity_id, $document_id, Request $request) {
    if ($entity_type === $entity_id) {
      // It is not a config entity, but a config object.
      $definition = $this->configMapperManager->getDefinition($entity_type);
      try {
        if ($this->translationService->checkConfigSourceStatus($entity_type)) {
          $this->messenger()
            ->addStatus($this->t('%label status checked successfully', ['%label' => $definition['title']]));
        }
        else {
          $this->messenger()
            ->addStatus(t('The import for %label is still pending.', ['%label' => $definition['title']]));
        }
      }
      catch (StrakerTranslateDocumentNotFoundException $exception) {
        $this->messenger()
          ->addError($this->t('Document %label was not found. Please upload again.', [
            '%label' => $definition['title'],
          ]));
      }
      catch (StrakerTranslateApiException $e) {
        $this->messenger()
          ->addError($this->t('%label status check failed. Please try again.',
            ['%label' => $definition['title']]));
      }
      return $this->redirectToConfigTranslateOverview($entity_type);
    }
    // Check if it's a field.
    if (substr($entity_type, -7) == '_fields') {
      // Hack for fields, the entity is field config.
      $entity_type = 'field_config';
    }
    $entity = $this->entityTypeManager()->getStorage($entity_type)->load($entity_id);
    try {
      if ($this->translationService->checkSourceStatus($entity)) {
        $this->messenger()->addStatus($this->t('%label status checked successfully', ['%label' => $entity->label()]));
      }
      else {
        $this->messenger()->addStatus(t('The import for %label is still pending.', ['%label' => $entity->label()]));
      }
    }
    catch (StrakerTranslateDocumentNotFoundException $exception) {
      $this->messenger()
        ->addError($this->t('Document %label was not found. Please upload again.', [
          '%label' => $entity->label(),
        ]));
    }
    catch (StrakerTranslateApiException $e) {
      $this->messenger()->addError($this->t('%label status check failed. Please try again.',
        ['%label' => $entity->label()]));
    }

    return $this->redirectToEntityTranslateOverview($entity_type, $entity_id);
  }

  /**
   *
   */
  public function download($entity_type, $entity_id, $file_id, $langcode, Request $request) {
    if ($entity_type === $entity_id) {
      // It is not a config entity, but a config object.
      $definition = $this->configMapperManager->getDefinition($entity_type);
      try {
        $success = $this->translationService->downloadConfig($entity_id, $file_id, $langcode);
        if ($success === TRUE) {
          $this->messenger()->addStatus($this->t('Translation to %langcode downloaded successfully', ['%langcode' => $langcode]));
        }
        elseif ($success === FALSE) {
          $mappers = $this->configMapperManager->getMappers();
          $this->translationService->setConfigTargetStatus($mappers[$entity_type], $langcode, StrakerTranslate::STATUS_ERROR);
          $this->messenger()->addError($this->t('%label @language translation download failed. Please try again.',
            ['%label' => $definition['title'], '@language' => $langcode]));
        }
      }
      catch (StrakerTranslateDocumentNotFoundException $exception) {
        $this->messenger()->addError($this->t('Document %label was not found. Please upload again.',
          ['%label' => $definition['title']]));
      }
      catch (StrakerTranslateApiException $e) {
        $mappers = $this->configMapperManager->getMappers();
        $this->translationService->setConfigTargetStatus($mappers[$entity_type], $langcode, StrakerTranslate::STATUS_ERROR);
        $this->messenger()->addError($this->t('%label @language translation download failed. Please try again.',
          ['%label' => $definition['title'], '@language' => $langcode]));
      }
      return $this->redirectToConfigTranslateOverview($entity_type);
    }
    // Check if it's a field.
    if (substr($entity_type, -7) == '_fields') {
      // Hack for fields, the entity is field config.
      $entity_type = 'field_config';
    }
    $entity = $this->entityTypeManager()->getStorage($entity_type)->load($entity_id);
    try {
      $success = $this->translationService->downloadDocument($entity, $file_id, $langcode);
      if ($success === TRUE) {
        $this->messenger()->addStatus($this->t('%label Translation to %langcode downloaded successfully', ['%label' => $entity->label(), '%langcode' => $langcode]));
      }
      elseif ($success === FALSE) {
        $this->translationService->setTargetStatus($entity, $langcode, StrakerTranslate::STATUS_ERROR);
        $this->messenger()->addError($this->t('%label @langcode translation download failed. Please try again.',
          ['%label' => $entity->label(), '@langcode' => $langcode]));
      }
    }
    catch (StrakerTranslateDocumentNotFoundException $exception) {
      $this->messenger()->addError($this->t('Document %label was not found. Please upload again.',
        ['%label' => $entity->label()]));
    }
    catch (StrakerTranslateApiException $e) {
      $this->translationService->setTargetStatus($entity, $langcode, StrakerTranslate::STATUS_ERROR);
      $this->messenger()->addError($this->t('%label @langcode translation download failed. Please try again.',
        ['%label' => $entity->label(), '@langcode' => $langcode]));
    }

    return $this->redirectToEntityTranslateOverview($entity_type, $entity_id);
  }

  /**
   * Redirect to config entity translation overview page.
   *
   * @param string $entity_type
   *   The config entity type id.
   * @param string $entity_id
   *   The config entity id.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   A redirect response.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function redirectToEntityTranslateOverview($entity_type, $entity_id) {
    $mappers = $this->configMapperManager->getMappers();
    if ($entity_type === 'field_config') {
      $field_config = FieldConfig::load($entity_id);
      $id = $field_config->getTargetEntityTypeId();
      /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
      $mapper = $mappers[$id . '_fields'];
      $mapper->setEntity($field_config);
      $entity_definition = $this->entityTypeManager->getDefinition($id);

      $uri = Url::fromRoute($mapper->getOverviewRouteName(), [$entity_type => $entity_id, $entity_definition->getBundleEntityType() => $field_config->getTargetBundle()]);
    }
    else {
      $mapper = $mappers[$entity_type];
      $uri = Url::fromRoute($mapper->getOverviewRouteName(), [$entity_type => $entity_id]);
    }
    return new RedirectResponse($uri->setAbsolute(TRUE)->toString());
  }

  /**
   * Redirect to config translation overview page.
   *
   * @param string $plugin_id
   *   The plugin id.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   A redirect response.
   */
  protected function redirectToConfigTranslateOverview($plugin_id) {
    $mappers = $this->configMapperManager->getMappers();
    $mapper = $mappers[$plugin_id];
    $uri = Url::fromRoute($mapper->getOverviewRouteName());
    return new RedirectResponse($uri->setAbsolute(TRUE)->toString());
  }

  /**
   * Generates the operation links for each language.
   *
   * @param array &$page
   *   The reference of the page build render array where we need to add the
   *   links to.
   * @param string $plugin_id
   *   The plugin id, which is needed for building the link. It could be the
   *   entity type id or the plugin id of the config mapper.
   * @param string $entity_id
   *   The entity id. If it's a config mapper and not an entity, it would be the
   *   plugin id.
   * @param int $target_status
   *   The target status for this language. This way we decide which link must
   *   be shown.
   * @param $langcode
   *   The langcode of the translation we are building the link to. Used for
   *   keying the link in the page array.
   * @param $locale
   *   Straker Translate locale we are creating the link for. Used for building the link
   *   itself.
   */
  protected function generateOperationsLinks(&$page, $plugin_id, $entity_id, $target_status, $mapper, $langcode) {
    if ($mapper instanceof ConfigEntityMapper) {
      /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
      $entity = $mapper->getEntity();
      $file_id = $this->translationService->getTargetFileId($entity, $langcode);
    }
    else {
      $file_id = $this->translationService->getConfigTargetFileId($mapper, $langcode);
    }

    if ($file_id === NULL) {
      // If we don't have a file id, we cannot do anything.
      return;
    }
    $route_params = [
      'entity_type' => $plugin_id,
      'entity_id' => $entity_id,
      'file_id' => $file_id,
      'langcode' => $langcode,
    ];
    if ($target_status == StrakerTranslate::STATUS_READY || $target_status == StrakerTranslate::STATUS_ERROR) {
      // Add the download link.
      $page['languages'][$langcode]['operations']['#links']['download'] = [
        'title' => $this->t('Download'),
        'url' => Url::fromRoute('straker_translate.config.download', $route_params),
      ];
    }
  }

}
