<?php

declare(strict_types=1);

namespace Drupal\flowdrop_workflow\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\flowdrop_workflow\Entity\FlowDropWorkflow;
use Drupal\flowdrop_workflow\Event\WorkflowDuplicatedEvent;
use Drupal\flowdrop_workflow\FlowDropWorkflowInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Form for duplicating an existing FlowDropWorkflow.
 *
 * Builds on ConfigEntityBase::createDuplicate(): the full graph (nodes,
 * edges, metadata), exposed ports and schema snapshots are carried over
 * as-is, while id/uuid are cleared so saving creates a new entity. The form
 * only collects a new label and machine name; ownership and timestamps are
 * re-stamped for the duplicating user on save.
 *
 * @property \Drupal\flowdrop_workflow\FlowDropWorkflowInterface $entity
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class FlowDropWorkflowDuplicateForm extends EntityForm {

  public function __construct(
    protected EventDispatcherInterface $eventDispatcher,
  ) {}

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

  /**
   * {@inheritdoc}
   *
   * Swaps the routed workflow for an unsaved duplicate so the rest of the
   * EntityForm machinery treats this as an "add" of a pre-filled entity.
   */
  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id): EntityInterface {
    $source = parent::getEntityFromRouteMatch($route_match, $entity_type_id);
    /** @var \Drupal\flowdrop_workflow\FlowDropWorkflowInterface $duplicate */
    $duplicate = $source->createDuplicate();
    $duplicate->setLabel((string) $this->t('@label (copy)', ['@label' => $source->label()]));
    return $duplicate;
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state): array {
    $form = parent::form($form, $form_state);

    $form['info'] = [
      '#markup' => $this->t('Creates a copy of the workflow, including all nodes, edges, exposed ports and settings.'),
    ];

    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#maxlength' => 255,
      '#default_value' => $this->entity->label(),
      '#required' => TRUE,
    ];

    $form['id'] = [
      '#type' => 'machine_name',
      '#default_value' => '',
      '#machine_name' => [
        'exists' => [FlowDropWorkflow::class, 'load'],
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  protected function actions(array $form, FormStateInterface $form_state): array {
    $actions = parent::actions($form, $form_state);
    $actions['submit']['#value'] = $this->t('Duplicate');
    return $actions;
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state): int {
    // Capture the source before saving; the source workflow is the routed
    // entity the duplicate was cloned from.
    $source = $this->getRouteMatch()->getParameter('flowdrop_workflow');
    $sourceId = $source instanceof FlowDropWorkflowInterface ? (string) $source->id() : NULL;

    // The copy belongs to the duplicating user. Timestamps need no handling:
    // preSave() re-stamps created/changed because the duplicate is new.
    $this->entity->setUid((int) $this->currentUser()->id());
    $result = $this->entity->save();

    // Let other modules propagate workflow-bound satellite config (e.g.
    // trigger configs) from the source to the new copy.
    if ($sourceId !== NULL && $sourceId !== '') {
      $this->eventDispatcher->dispatch(
        new WorkflowDuplicatedEvent($sourceId, $this->entity),
      );
    }

    $this->messenger()->addStatus($this->t('Workflow %label has been created.', [
      '%label' => $this->entity->label(),
    ]));
    $form_state->setRedirectUrl($this->entity->toUrl('collection'));
    return $result;
  }

}
