<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Form;

use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\flowdrop_interrupt\Plugin\InterruptHandler\HitlInterruptHandlerInterface;
use Drupal\flowdrop_interrupt\Service\InterruptHandlerPluginManager;
use Drupal\flowdrop_interrupt\Service\InterruptManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form for resolving a pending interrupt.
 *
 * Dispatches form building, validation, and response extraction to the
 * type-specific interrupt handler plugin. The form itself only knows how
 * to wrap the interrupt's message and back/cancel actions; per-type
 * widget rendering lives in the plugin.
 *
 * Plugins that do not implement {@see HitlInterruptHandlerInterface} are
 * operational (e.g. `workflow_execution`) and cannot be resolved through
 * this form — they're resolved by runtime subscribers instead.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class ResolveInterruptForm extends FormBase {

  public function __construct(
    protected readonly InterruptManagerInterface $interruptManager,
    protected readonly InterruptHandlerPluginManager $handlerManager,
  ) {}

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

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

  /**
   * {@inheritdoc}
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param string $interrupt_id
   *   The interrupt UUID passed from the route.
   */
  public function buildForm(array $form, FormStateInterface $form_state, string $interrupt_id = ''): array {
    $interrupt = $this->interruptManager->getInterrupt($interrupt_id);

    if (!$interrupt || !$interrupt->isPending()) {
      $form['unavailable'] = [
        '#markup' => '<p>' . $this->t('This interrupt is no longer available.') . '</p>',
      ];
      return $form;
    }

    $form_state->set('interrupt_id', $interrupt_id);

    $form['interrupt_message'] = [
      '#type' => 'item',
      '#markup' => '<p>' . Html::escape($interrupt->getMessage()) . '</p>',
    ];

    $handler = $this->handlerManager->loadHandler($interrupt->getType()->value);
    if ($handler instanceof HitlInterruptHandlerInterface) {
      $form = $handler->buildResolveForm($form, $form_state, $interrupt);
    }
    else {
      // Operational interrupt — not user-resolvable through this form.
      $form['not_resolvable'] = [
        '#markup' => '<p>' . $this->t('This interrupt is resolved automatically by the runtime and cannot be answered here.') . '</p>',
      ];
      $form['actions'] = ['#type' => 'actions'];
    }

    // Standard back / cancel actions appended to whatever the handler built.
    if (!isset($form['actions'])) {
      $form['actions'] = ['#type' => 'actions'];
    }
    $form['actions']['back'] = [
      '#type' => 'link',
      '#title' => $this->t('Back to inbox'),
      '#url' => Url::fromRoute('flowdrop_interrupt.inbox'),
      '#attributes' => ['class' => ['button']],
    ];
    if ($interrupt->access('cancel')) {
      $form['actions']['cancel'] = [
        '#type' => 'link',
        '#title' => $this->t('Cancel interrupt'),
        '#url' => Url::fromRoute('flowdrop_interrupt.cancel_confirm', [
          'interrupt_id' => $interrupt_id,
        ]),
        '#attributes' => ['class' => ['button', 'button--danger']],
      ];
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    $interrupt_id = $form_state->get('interrupt_id');
    $interrupt = $this->interruptManager->getInterrupt($interrupt_id);

    if (!$interrupt || !$interrupt->isPending()) {
      $form_state->setError($form, $this->t('This interrupt is no longer available.'));
      return;
    }

    $handler = $this->handlerManager->loadHandler($interrupt->getType()->value);
    if ($handler instanceof HitlInterruptHandlerInterface) {
      $handler->validateForm($form, $form_state, $interrupt);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $interrupt_id = $form_state->get('interrupt_id');
    $interrupt = $this->interruptManager->getInterrupt($interrupt_id);

    if (!$interrupt || !$interrupt->isPending()) {
      $this->messenger()->addError($this->t('This interrupt is no longer available.'));
      $form_state->setRedirect('flowdrop_interrupt.inbox');
      return;
    }

    $handler = $this->handlerManager->loadHandler($interrupt->getType()->value);
    if (!$handler instanceof HitlInterruptHandlerInterface) {
      $this->messenger()->addError($this->t('This interrupt cannot be resolved through the form.'));
      $form_state->setRedirect('flowdrop_interrupt.inbox');
      return;
    }

    $rawResponse = $handler->extractResponseFromForm($form_state, $interrupt);
    $responseData = $handler->normalizeResponse($rawResponse, $interrupt);
    $user_id = (int) $this->currentUser()->id();

    try {
      $this->interruptManager->resolveInterrupt($interrupt_id, $responseData, $user_id);
      $this->messenger()->addStatus($this->t('Your response has been submitted.'));
    }
    catch (\Throwable $e) {
      $this->messenger()->addError($this->t('Failed to submit response: @message', [
        '@message' => $e->getMessage(),
      ]));
    }

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

}
