<?php

namespace Drupal\uw_cfg_common\Form;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form class for the content access form.
 */
class UwContentModerationForm extends ConfirmFormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The nid (node id).
   *
   * @var int
   */
  protected $nid;

  /**
   * The vid (version id).
   *
   * @var int
   */
  protected $vid;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Instantiates this form class.
    return new static(
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'uw_content_moderation_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $nid = NULL, $vid = NULL, $status = NULL) {

    // Set the node, version id and status.
    $this->nid = $nid;
    $this->vid = $vid;
    $this->status = $status;

    // Get the form from the parent, we need this to ensure
    // that we have all the components (like confirm/cancel)
    // load with this form as well.
    $form = parent::buildForm($form, $form_state);

    // Unset the description, we want to replace it with our
    // description based on the node status.
    unset($form['description']);

    // Set the description form element.
    $form['description'] = [
      '#type' => 'markup',
    ];

    // Set the description based on the node status.
    if ($this->status) {
      $form['description']['#markup'] = $this->t('Are you sure that you want to unpublish the live revision of this content?');
    }
    else {
      $form['description']['#markup'] = $this->t('Are you sure that you want to publish the live revision of this content?');
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    // If we are unpublishing, load the latest revision node.
    if ($this->status) {

      // Load the node with the nid.
      $node = $this->entityTypeManager->getStorage('node')->load($this->nid);

      // Get all the revisions for the current node.
      $revision_ids = $this->entityTypeManager->getStorage('node')->revisionIds($node);

      // Get the node object with that latest revision, which is the end
      // of the revision ids list.
      $node = $this->entityTypeManager->getStorage('node')->loadRevision(end($revision_ids));
    }

    // If we are publishing, load the node with the nid.
    else {

      // Get the node object.
      $node = $this->entityTypeManager->getStorage('node')->loadRevision($this->vid);
    }

    // If the node is currently published, then we want to
    // unpublish this content, which will mean to move from
    // two statesL upublish and draft.
    if ($this->status) {

      // First set the node to unpublished, we need to do this
      // because moving it to just draft will not cause it to
      // become unpublished.
      $node->set('moderation_state', 'uw_wf_unpublished');

      // Save the node to move it to unpublished.
      $saved_status = $node->save();

      // Now set the node moderation state to draft.
      $node->set('moderation_state', 'draft');

      // Save the node with the moderation state at draft.
      $saved_status = $node->save();
    }

    // If the node is already unpublished, we want to move to the
    // published moderation state.
    else {

      // Set the moderation state to publish.
      $node->set('moderation_state', 'published');

      // Save the node with the moderation state at published.
      $saved_status = $node->save();
    }

    // Set the options for the URL.
    $options = ['absolute' => TRUE];

    // Return the URL back to the node.
    $url = Url::fromRoute('entity.node.canonical', ['node' => $this->nid], $options);

    // Adding the redirect back to the node.
    $form_state->setRedirectUrl($url);

    // If the saved status is SAVED_UPDATED (2), means that we successfully changed
    // the moderation state so set the message appropriately.
    if ($saved_status == SAVED_UPDATED) {

      if ($this->status) {
        $this->messenger()->addStatus($this->t('You have successfully unpublished this content.'));
      }
      else {
        $this->messenger()->addStatus($this->t('You have successfully published this content.'));
      }
    }

    // If the saved status is anything else, there was an
    // error trying to change the moderation state so set
    // the message appropriately.
    else {

      if ($this->status) {
        $this->messenger()->addError($this->t('There was an error trying to unpublish this content.'));
      }
      else {
        $this->messenger()->addError($this->t('There was an error trying to publish this content.'));
      }
    }
  }

  /**
   * Returns the question to ask the user.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The form question. The page title will be set to this value.
   */
  public function getQuestion() {

    // Get the node object.
    $node = $this->entityTypeManager->getStorage('node')->load($this->nid);

    // Set the question (title of page) based on node status.
    if ($this->status) {

      // Return the question to see if they want to publish the node.
      return t('Unpublish %node_title?', ['%node_title' => $node->getTitle()]);
    }
    else {

      // Return the question to see if they want to publish the node.
      return t('Publish %node_title?', ['%node_title' => $node->getTitle()]);
    }
  }

  /**
   * Returns the route to go to if the user cancels the action.
   *
   * @return \Drupal\Core\Url
   *   A URL object.
   */
  public function getCancelUrl() {

    // Set the options for the URL.
    $options = ['absolute' => TRUE];

    // Return the URL back to the node.
    return Url::fromRoute('entity.node.canonical', ['node' => $this->nid], $options);
  }

}