<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Plugin\InterruptHandler;

use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_interrupt\Attribute\FlowDropInterruptHandler;
use Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Handler for Timer interrupts created by Delay/Schedule nodes.
 *
 * Two resolution paths:
 * - **Scheduled (normal):** the cron sweep calls `shouldResolveNow()`
 *   against the entity's `scheduled_at` and, once due, resolves with
 *   `buildAutoResponse()` — the `resolved_by_timer` flag tells the node's
 *   `resume()` the clock fired.
 * - **HITL (skip-the-wait):** the interrupt appears in the inbox as a
 *   "Waiting until …" card with a single "Resume now" button. Resolving it
 *   early resumes the pipeline immediately; the response carries no
 *   `resolved_by_timer` flag, so `resume()` reports a human skip.
 *
 * @internal
 */
#[FlowDropInterruptHandler(
  id: 'timer',
  label: new TranslatableMarkup('Timer'),
  description: 'Time-based pause resolved automatically when due',
)]
final class TimerInterruptHandler extends AbstractInterruptHandler implements ScheduledInterruptHandlerInterface, HitlInterruptHandlerInterface {

  use StringTranslationTrait;

  /**
   * The date formatter.
   */
  protected DateFormatterInterface $dateFormatter;

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ): static {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->dateFormatter = $container->get('date.formatter');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function getNextSweepAt(FlowDropInterruptInterface $interrupt): ?int {
    return $interrupt->getScheduledAt();
  }

  /**
   * {@inheritdoc}
   */
  public function shouldResolveNow(FlowDropInterruptInterface $interrupt): bool {
    $scheduledAt = $interrupt->getScheduledAt();
    return $scheduledAt !== NULL && $scheduledAt <= time();
  }

  /**
   * {@inheritdoc}
   */
  public function buildAutoResponse(FlowDropInterruptInterface $interrupt): mixed {
    return [
      'resolved_by_timer' => TRUE,
      'fired_at' => time(),
      // Carried in the response because ResolvedInterruptInterface exposes
      // response data only — the node's resume() reads the original fire
      // time from here to compute drift.
      'scheduled_at' => $interrupt->getScheduledAt(),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildResolveForm(array $form, FormStateInterface $formState, FlowDropInterruptInterface $interrupt): array {
    $scheduledAt = $interrupt->getScheduledAt();

    $form['timer_details'] = [
      '#type' => 'container',
      '#attributes' => ['class' => ['flowdrop-timer-details']],
    ];
    if ($scheduledAt !== NULL) {
      $form['timer_details']['scheduled'] = [
        '#type' => 'item',
        '#title' => $this->t('Waiting until'),
        '#markup' => $this->dateFormatter->format($scheduledAt, 'long'),
      ];
    }
    $form['timer_details']['hint'] = [
      '#type' => 'item',
      '#markup' => '<p>' . $this->t('Resuming now skips the remaining wait.') . '</p>',
    ];

    $form['actions'] = ['#type' => 'actions'];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Resume now'),
      '#button_type' => 'primary',
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   *
   * No validation — clicking Resume now is an unconditional skip.
   */
  public function validateForm(array &$form, FormStateInterface $formState, FlowDropInterruptInterface $interrupt): void {}

  /**
   * {@inheritdoc}
   *
   * No `resolved_by_timer` flag: the node's resume() reads its absence as
   * a human skip.
   */
  public function extractResponseFromForm(FormStateInterface $formState, FlowDropInterruptInterface $interrupt): mixed {
    return [
      'resolved_by_timer' => FALSE,
      'skipped' => TRUE,
      'resumed_at' => time(),
      'scheduled_at' => $interrupt->getScheduledAt(),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function normalizeResponse(mixed $raw, FlowDropInterruptInterface $interrupt): mixed {
    if (is_array($raw)) {
      return $raw + ['resolved_by_timer' => FALSE];
    }
    return ['resolved_by_timer' => FALSE, 'skipped' => TRUE, 'resumed_at' => time()];
  }

}
