<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Form;

use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\flowdrop_interrupt\Service\InterruptManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Confirms dismissal (cancellation) of one or more pending interrupts.
 *
 * The target UUIDs are handed over from the inbox form via private tempstore,
 * so a refresh or shared link can't replay a stale dismissal.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class DismissInterruptsConfirmForm extends ConfirmFormBase {

  private const TEMPSTORE_COLLECTION = 'flowdrop_interrupt';

  /**
   * The interrupt UUIDs queued for dismissal.
   *
   * @var array<int, string>
   */
  private array $ids = [];

  public function __construct(
    private readonly PrivateTempStoreFactory $tempStoreFactory,
    private readonly InterruptManagerInterface $interruptManager,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('tempstore.private'),
      $container->get('flowdrop_interrupt.manager'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'flowdrop_interrupt_dismiss_confirm_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $stored = $this->tempStoreFactory->get(self::TEMPSTORE_COLLECTION)->get('dismiss_ids');

    if (!is_array($stored) || $stored === []) {
      // Nothing queued (direct hit, expired tempstore, or already handled).
      throw new NotFoundHttpException();
    }

    $this->ids = array_values(array_unique(array_map('strval', $stored)));

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function getQuestion(): \Stringable {
    return $this->formatPlural(
      count($this->ids),
      'Dismiss this pending interrupt?',
      'Dismiss these @count pending interrupts?',
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription(): \Stringable {
    return $this->t('Dismissing cancels the interrupt and the workflow run waiting on it cannot be resumed. This cannot be undone.');
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmText(): \Stringable {
    return $this->t('Dismiss');
  }

  /**
   * {@inheritdoc}
   */
  public function getCancelUrl(): Url {
    return Url::fromRoute('flowdrop_interrupt.inbox');
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $store = $this->tempStoreFactory->get(self::TEMPSTORE_COLLECTION);
    $ids = $store->get('dismiss_ids');
    $store->delete('dismiss_ids');

    if (!is_array($ids) || $ids === []) {
      $this->messenger()->addWarning($this->t('Nothing to dismiss.'));
      $form_state->setRedirect('flowdrop_interrupt.inbox');
      return;
    }

    $dismissed = 0;
    $skipped = 0;
    foreach (array_unique(array_map('strval', $ids)) as $uuid) {
      // Re-check cancel access at the point of consumption: the inbox only
      // queues the user's own interrupts, but the tempstore handover must
      // not be the boundary — no producer of dismiss_ids may dismiss an
      // interrupt the operator could not cancel directly.
      $interrupt = $this->interruptManager->getInterrupt($uuid);
      if ($interrupt === NULL || !$interrupt->access('cancel')) {
        $skipped++;
        continue;
      }
      if ($this->interruptManager->cancelInterrupt($uuid)) {
        $dismissed++;
      }
      else {
        $skipped++;
      }
    }

    if ($dismissed > 0) {
      $this->messenger()->addStatus($this->formatPlural(
        $dismissed,
        'Dismissed 1 interrupt.',
        'Dismissed @count interrupts.',
      ));
    }
    if ($skipped > 0) {
      $this->messenger()->addWarning($this->formatPlural(
        $skipped,
        '1 interrupt could not be dismissed (it may have already been resolved).',
        '@count interrupts could not be dismissed (they may have already been resolved).',
      ));
    }

    $form_state->setRedirect('flowdrop_interrupt.inbox');
  }

}
