<?php

namespace Drupal\sector_workflow;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A utility class to improve the core workflows user interface and experience.
 *
 * This class provides helper methods for content moderation workflows,
 * including revision management, local task customization, and user interface
 * improvements.
 *
 * Example:
 * @code
 * \Drupal::classResolver(SectorWorkflow::class)->getRevisionDate($revision);
 * @endcode
 */
class SectorWorkflow implements ContainerInjectionInterface {

  use StringTranslationTrait;

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

  /**
   * The current route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The content moderation moderation information.
   *
   * @var \Drupal\content_moderation\ModerationInformationInterface
   */
  protected $moderationInfo;

  /**
   * Instantiates a SectorWorkflow object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match service.
   * @param \Drupal\content_moderation\ModerationInformationInterface $moderation_info
   *   The content moderation information service.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    RouteMatchInterface $route_match,
    ModerationInformationInterface $moderation_info
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->routeMatch = $route_match;
    $this->moderationInfo = $moderation_info;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('current_route_match'),
      $container->get('content_moderation.moderation_information')
    );
  }

  /**
   * Get the new text for the local task titles depending on the route passed.
   *
   * @param string $task_name
   *   The name of the local task.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The translated text for the local task.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getNewTextForLocalTask(string $task_name): TranslatableMarkup {
    switch ($task_name) {
      case 'content_moderation.workflows:node.latest_version_tab':
        return $this->t('View draft');

      case 'entity.node.edit_form':
        return $this->getEditFormTaskText();

      case 'entity.node.canonical':
        return $this->getCanonicalTaskText();

      default:
        return $this->t('View');
    }
  }

  /**
   * Gets the appropriate text for the edit form local task.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The translated text for the edit form task.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getEditFormTaskText(): TranslatableMarkup {
    /** @var \Drupal\node\NodeInterface|null $node */
    $node = $this->routeMatch->getParameter('node');
    
    if (!$node) {
      return $this->t('Edit draft');
    }

    $out = $this->t('Edit draft');
    $parent_node = $this->entityTypeManager->getStorage('node')->load($node->id());
    
    if ($parent_node && !$this->moderationInfo->hasPendingRevision($node) && $parent_node->isPublished()) {
      $out = $this->t('New draft');
    }

    return $out;
  }

  /**
   * Gets the appropriate text for the canonical local task.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The translated text for the canonical task.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getCanonicalTaskText(): TranslatableMarkup {
    $route_name = $this->routeMatch->getRouteName();
    /** @var \Drupal\node\NodeInterface|null $node */
    $node = $this->routeMatch->getParameter('node');
    
    if (!$node) {
      return $this->t('View published');
    }

    if (!$node->isPublished()) {
      $out = $this->t('View draft');
      
      if (in_array($route_name, ['entity.node.latest_version', 'entity.node.edit_form'], TRUE)) {
        $parent_node = $this->entityTypeManager->getStorage('node')->load($node->id());
        if ($parent_node && $parent_node->isPublished()) {
          $out = $this->t('View published');
        }
      }
      
      return $out;
    }

    return $this->t('View published');
  }

  /**
   * Gets the (formatted) date from the given revision.
   *
   * @param \Drupal\node\NodeInterface $revision
   *   The revision node to get the date from.
   * @param string $format
   *   The date format string. Defaults to a readable format.
   *
   * @return string
   *   The formatted revision date.
   *
   * @throws \Exception
   *   If the date formatting fails.
   */
  public function getRevisionDate(NodeInterface $revision, string $format = 'l \t\h\e jS \of F Y h:i:s A'): string {
    $revision_timestamp = $revision->getRevisionCreationTime();
    $revision_date_obj = new \DateTime();
    $revision_date_obj->setTimestamp($revision_timestamp);
    
    return $revision_date_obj->format($format);
  }

  /**
   * Gets the author for the given revision.
   *
   * @param \Drupal\node\NodeInterface $revision
   *   The revision node to get the author from.
   *
   * @return string
   *   The revision author's account name, or an empty string if not available.
   */
  public function getRevisionAuthor(NodeInterface $revision): string {
    $revision_user = $revision->getRevisionUser();
    
    if (!$revision_user) {
      return '';
    }
    
    return $revision_user->getAccountName();
  }

}

