<?php

declare(strict_types=1);

namespace Drupal\Tests\flowdrop_runtime\Unit\Event;

use Drupal\flowdrop_runtime\Event\PlaygroundContext;
use Drupal\Tests\UnitTestCase;

/**
 * Covers PlaygroundContext construction and hierarchy sanitization.
 *
 * The pipeline execution context is JSON-encoded and may contain
 * malformed hierarchy items if a buggy emitter wrote it. The context
 * factory must reject those silently so subscribers always receive a
 * well-formed list.
 *
 * @coversDefaultClass \Drupal\flowdrop_runtime\Event\PlaygroundContext
 * @group flowdrop_runtime
 */
class PlaygroundContextTest extends UnitTestCase {

  /**
   * Returns NULL when no session id is present.
   */
  public function testReturnsNullWithoutSessionId(): void {
    $this->assertNull(PlaygroundContext::fromPipelineContext([]));
    $this->assertNull(PlaygroundContext::fromPipelineContext(['playground' => []]));
    $this->assertNull(PlaygroundContext::fromPipelineContext(['playground' => ['session_id' => '']]));
  }

  /**
   * A minimal context yields a context with empty hierarchy.
   */
  public function testEmptyHierarchyByDefault(): void {
    $ctx = PlaygroundContext::fromPipelineContext([
      'playground' => ['session_id' => 'sess-1'],
    ]);

    $this->assertNotNull($ctx);
    $this->assertSame('sess-1', $ctx->getSessionId());
    $this->assertSame([], $ctx->getHierarchy());
  }

  /**
   * Well-formed hierarchy items pass through unchanged.
   */
  public function testHierarchyPassesThroughWhenWellFormed(): void {
    $ctx = PlaygroundContext::fromPipelineContext([
      'playground' => [
        'session_id' => 'sess-1',
        'hierarchy' => [
          ['id' => 'wf:parent', 'label' => 'Calculator User'],
          ['id' => 'wf:child', 'label' => 'Calculator', 'icon' => 'mdi:calculator'],
        ],
      ],
    ]);

    $this->assertNotNull($ctx);
    $this->assertSame([
      ['id' => 'wf:parent', 'label' => 'Calculator User'],
      ['id' => 'wf:child', 'label' => 'Calculator', 'icon' => 'mdi:calculator'],
    ], $ctx->getHierarchy());
  }

  /**
   * Malformed hierarchy entries are dropped silently, well-formed are kept.
   */
  public function testMalformedHierarchyItemsAreDropped(): void {
    $ctx = PlaygroundContext::fromPipelineContext([
      'playground' => [
        'session_id' => 'sess-1',
        'hierarchy' => [
          ['id' => 'wf:ok', 'label' => 'Valid'],
          // Missing label.
          ['id' => 'wf:no-label'],
          // Empty label.
          ['id' => 'wf:empty', 'label' => ''],
          // Non-array entry.
          'just a string',
          // Non-string icon — entry survives, icon is omitted.
          ['id' => 'wf:noicon', 'label' => 'Kept', 'icon' => 42],
        ],
      ],
    ]);

    $this->assertSame([
      ['id' => 'wf:ok', 'label' => 'Valid'],
      ['id' => 'wf:noicon', 'label' => 'Kept'],
    ], $ctx->getHierarchy());
  }

  /**
   * A non-array hierarchy field is replaced with an empty list.
   */
  public function testNonArrayHierarchyIsIgnored(): void {
    $ctx = PlaygroundContext::fromPipelineContext([
      'playground' => [
        'session_id' => 'sess-1',
        'hierarchy' => 'not an array',
      ],
    ]);

    $this->assertSame([], $ctx->getHierarchy());
  }

}
