<?php

namespace Drupal\straker_translate\Form;

use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\straker_translate\Entity\StrakerTranslateConfigMetadata;
use Drupal\config_translation\ConfigEntityMapper;
use Drupal\config_translation\ConfigNamesMapper;
use Drupal\straker_translate\Entity\StrakerTranslateContentMetadata;
use Drupal\straker_translate\Exception\StrakerTranslateApiException;
use Drupal\straker_translate\StrakerTranslateConfigTranslationServiceInterface;
use Drupal\straker_translate\StrakerTranslateContentTranslationServiceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Show a warning before disassociate all content.
 */
class StrakerTranslateDisassociateAllConfirmForm extends ConfirmFormBase {

  /**
   * The Straker Translate content translation service.
   *
   * @var \Drupal\straker_translate\StrakerTranslateContentTranslationServiceInterface
   */
  protected $contentTranslationService;

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

  /**
   * Constructs a new StrakerTranslateDisassociateAllConfirmForm object.
   *
   * @param \Drupal\straker_translate\StrakerTranslateContentTranslationServiceInterface $content_translation_service
   *   The Straker Translate content translation service.
   * @param \Drupal\straker_translate\StrakerTranslateConfigTranslationServiceInterface $config_translation_service
   *   The Straker Translate config translation service.
   */
  public function __construct(StrakerTranslateContentTranslationServiceInterface $content_translation_service, StrakerTranslateConfigTranslationServiceInterface $config_translation_service) {
    $this->contentTranslationService = $content_translation_service;
    $this->configTranslationService = $config_translation_service;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('straker_translate.content_translation'),
      $container->get('straker_translate.config_translation')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormID() {
    return 'straker_translate_disassociate_all_config_form';
  }

  /**
   * {@inheritdoc}
   */
  public function getFormName() {
    return 'straker_translate_disassociate_all_config_form';
  }

  /**
   * {@inheritdoc}
   */
  public function getQuestion() {
    return $this->t('Are you sure you want to disassociate everything from Straker?');
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription() {
    $string = '<p>' . $this->t("This is useful for switching between different environments. It will disassociate the content from Straker Verify content so your next changes won't alter what is getting worked on from the Straker Verify.") . '</p>';
    $string .= '<p>' . $this->t("This option should only be used if you still want the translations to be completed (and eventually billed for) in Straker's Verify.") . '</p>';
    $string .= '<p>' . $this->t("Check if you may want to use the Cancel option instead.") . '</p>';
    $string .= '<p>' . parent::getDescription() . '</p>';
    return $string;
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmText() {
    return $this->t('Disassociate');
  }

  /**
   * {@inheritdoc}
   */
  public function getCancelUrl() {
    return new Url('straker_translate.settings');
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->disassociateAllTranslations();
    $form_state->setRedirectUrl($this->getCancelUrl());
  }

  /**
   * Disassociate all content and config translations.
   */
  public function disassociateAllTranslations() {
    $error = FALSE;

    $error &= $this->disassociateAllContentTranslations();
    $error &= $this->disassociateAllConfigTranslations();

    if ($error) {
      $this->messenger()->addWarning($this->t('Some translations may have been disassociated, but some failed.'));
    }
    else {
      $this->messenger()->addStatus($this->t('All translations have been disassociated.'));
    }
  }

  /**
   * Disassociate all config translations.
   */
  protected function disassociateAllConfigTranslations() {
    $error = FALSE;

    /** @var \Drupal\straker_translate\Entity\StrakerTranslateConfigMetadata[] $all_config_metadata */
    $all_config_metadata = StrakerTranslateConfigMetadata::loadMultiple();
    foreach ($all_config_metadata as $config_metadata) {
      try {
        $mapper = $config_metadata->getConfigMapper();
        if ($mapper instanceof ConfigEntityMapper) {
          $entity = $mapper->getEntity();
          $this->configTranslationService->deleteMetadata($entity);
        }
        elseif ($mapper instanceof ConfigNamesMapper) {
          /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
          $this->configTranslationService->deleteConfigMetadata($mapper->getPluginId());
        }
      }
      catch (StrakerTranslateApiException $exception) {
        $error = TRUE;
        if (isset($mapper)) {
          if ($mapper instanceof ConfigEntityMapper) {
            $this->messenger()->addError(t('The deletion of %title failed. Please try again.', ['%title' => $mapper->getEntity()->label()]));
          }
          else {
            /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
            $this->messenger()->addError(t('The deletion of %title failed. Please try again.', ['%title' => $mapper->getPluginId()]));
          }
        }
      }
    }
    return $error;
  }

  /**
   * Disassociate all content translations.
   */
  protected function disassociateAllContentTranslations() {
    $error = FALSE;

    /** @var \Drupal\straker_translate\Entity\StrakerTranslateContentMetadata[] $all_content_metadata */
    $all_content_metadata = StrakerTranslateContentMetadata::loadMultiple();
    foreach ($all_content_metadata as $content_metadata) {
      try {
        $content_metadata->delete();
      }
      catch (StrakerTranslateApiException $exception) {
        $error = TRUE;
        $this->messenger()->addError(t('The disassociation of @entity_type %title failed. Please try again.', ['@entity_type' => $content_metadata->getContentEntityTypeId(), '%title' => $content_metadata->id()]));
      }
    }
    if ($error) {
      $this->messenger()->addWarning($this->t('Some translations may have been disassociated, but some failed.'));
    }
    else {
      $this->messenger()->addStatus($this->t('All translations have been disassociated.'));
    }
    return $error;
  }

}
