<?php

declare(strict_types=1);

namespace Drupal\Tests\flowdrop_interrupt\Unit\Handler;

use Drupal\flowdrop_interrupt\DTO\ExecutionStamp;
use Drupal\flowdrop_interrupt\DTO\InterruptCreationData;
use Drupal\flowdrop_interrupt\Entity\FlowDropInterruptInterface;
use Drupal\flowdrop_interrupt\Enum\InterruptDirection;
use Drupal\flowdrop_interrupt\Enum\InterruptType;
use Drupal\flowdrop_interrupt\Handler\HitlInterruptMessageHandler;
use Drupal\flowdrop_interrupt\Message\HitlInterruptMessage;
use Drupal\flowdrop_interrupt\Service\InterruptFactoryInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;

/**
 * @coversDefaultClass \Drupal\flowdrop_interrupt\Handler\HitlInterruptMessageHandler
 * @group flowdrop_interrupt
 */
class HitlInterruptMessageHandlerTest extends UnitTestCase {

  use ProphecyTrait;

  /**
   * Tests that supports() returns the message class name.
   */
  public function testSupportsReturnsMessageClass(): void {
    $this->assertSame(HitlInterruptMessage::class, HitlInterruptMessageHandler::supports());
  }

  /**
   * Tests that handle projects message and stamp onto creation data.
   */
  public function testHandleProjectsMessageAndStampOntoCreationData(): void {
    $entity = $this->prophesize(FlowDropInterruptInterface::class)->reveal();
    $factory = $this->prophesize(InterruptFactoryInterface::class);
    $factory->create(Argument::that(function (InterruptCreationData $data) {
      return $data->type === InterruptType::SchemaForm
        && $data->workflowId === 'wf'
        && $data->nodeId === 'node'
        && $data->message === 'Approve?'
        && $data->schema === ['type' => 'boolean']
        && $data->defaultValue === TRUE
        && $data->pipelineId === 'pipe'
        && $data->sessionId === 7
        && $data->expiresIn === 600
        && $data->assignedToUid === 42
        && $data->jobId === 99
        && $data->direction === InterruptDirection::Outward
        && $data->context === ['k' => 'v'];
    }))->shouldBeCalled()->willReturn($entity);

    $handler = new HitlInterruptMessageHandler($factory->reveal());
    $result = $handler->handle(
      new HitlInterruptMessage(
        type: InterruptType::SchemaForm,
        message: 'Approve?',
        schema: ['type' => 'boolean'],
        defaultValue: TRUE,
        expiresIn: 600,
        assignedToUid: 42,
        context: ['k' => 'v'],
      ),
      new ExecutionStamp(
        workflowId: 'wf',
        nodeId: 'node',
        pipelineId: 'pipe',
        sessionId: 7,
        jobId: 99,
      ),
    );

    $this->assertSame($entity, $result);
  }

  /**
   * Tests that handle always stamps outward direction regardless of stamp.
   */
  public function testHandleAlwaysStampsOutwardDirectionRegardlessOfStamp(): void {
    $entity = $this->prophesize(FlowDropInterruptInterface::class)->reveal();
    $factory = $this->prophesize(InterruptFactoryInterface::class);
    $factory->create(Argument::that(fn (InterruptCreationData $d) => $d->direction === InterruptDirection::Outward))
      ->shouldBeCalled()->willReturn($entity);

    $handler = new HitlInterruptMessageHandler($factory->reveal());
    // Stamp says Inward; HITL handler ignores it.
    $handler->handle(
      new HitlInterruptMessage(message: 'm'),
      new ExecutionStamp(workflowId: 'w', nodeId: 'n', direction: InterruptDirection::Inward),
    );
  }

}
