<?php

namespace Drupal\Tests\eb\Unit;

use Drupal\eb\Entity\EbDefinition;
use Drupal\eb\Exception\ValidationException;
use Drupal\eb\PluginManager\EbExtensionPluginManager;
use Drupal\eb\Service\Dependency\DependencyResolver;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\eb\Service\DefinitionFactory;
use PHPUnit\Framework\TestCase;

/**
 * Edge case and error condition tests for flat YAML format.
 *
 * @group eb
 */
class EdgeCaseTest extends TestCase {

  /**
   * Creates a mock extension manager.
   *
   * @return \Drupal\eb\PluginManager\EbExtensionPluginManager
   *   The mock extension manager.
   */
  protected function createExtensionManagerMock(): EbExtensionPluginManager {
    $mock = $this->createMock(EbExtensionPluginManager::class);
    $mock->method('getExtensions')->willReturn([]);
    return $mock;
  }

  /**
   * Creates a mock entity type manager.
   *
   * @return \Drupal\Core\Entity\EntityTypeManagerInterface
   *   The mock entity type manager.
   */
  protected function createEntityTypeManagerMock(): EntityTypeManagerInterface {
    $test = $this;
    $storage = $this->createMock(EntityStorageInterface::class);
    $storage->method('create')->willReturnCallback(
          function ($values) use ($test) {
              $definition = $test->createMock(EbDefinition::class);
              $definition->method('id')->willReturn($values['id'] ?? 'test');
              $definition->method('label')->willReturn($values['label'] ?? 'Test');
              return $definition;
          }
      );

    $mock = $this->createMock(EntityTypeManagerInterface::class);
    $mock->method('getStorage')->willReturn($storage);
    return $mock;
  }

  /**
   * Tests empty YAML handling.
   */
  public function testEmptyYamlHandling(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    // Empty data should pass validation (no required arrays).
    $definition = $factory->createFromYaml([], 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests hierarchical format is rejected.
   */
  public function testHierarchicalFormatRejected(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $this->expectException(ValidationException::class);
    $this->expectExceptionMessageMatches('/hierarchical.*no longer supported/i');

    $factory->createFromYaml(
          [
            'entities' => [
          [
            'entity_type' => 'node',
            'bundles' => [
          ['bundle_id' => 'test'],
            ],
          ],
            ],
          ], 'test.yml'
      );
  }

  /**
   * Tests missing required bundle fields.
   */
  public function testMissingBundleFields(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $this->expectException(ValidationException::class);
    $this->expectExceptionMessageMatches('/bundle_definitions.*entity_type/');

    $factory->createFromYaml(
          [
            'bundle_definitions' => [
          [
            'bundle_id' => 'test',
            'label' => 'Test',
          // Missing entity_type.
          ],
            ],
          ], 'test.yml'
      );
  }

  /**
   * Tests missing required field definition keys.
   */
  public function testMissingFieldDefinitionKeys(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $this->expectException(ValidationException::class);
    $this->expectExceptionMessageMatches('/field_definitions.*field_type/');

    $factory->createFromYaml(
          [
            'bundle_definitions' => [
          [
            'entity_type' => 'node',
            'bundle_id' => 'test',
            'label' => 'Test',
          ],
            ],
            'field_definitions' => [
            [
              'entity_type' => 'node',
              'bundle' => 'test',
              'field_name' => 'field_test',
            // Missing field_type.
            ],
            ],
          ], 'test.yml'
      );
  }

  /**
   * Tests missing display field definition keys.
   */
  public function testMissingDisplayFieldDefinitionKeys(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $this->expectException(ValidationException::class);
    $this->expectExceptionMessageMatches('/display_field_definitions.*display_type/');

    $factory->createFromYaml(
          [
            'bundle_definitions' => [
          [
            'entity_type' => 'node',
            'bundle_id' => 'test',
            'label' => 'Test',
          ],
            ],
            'display_field_definitions' => [
            [
              'entity_type' => 'node',
              'bundle' => 'test',
              'mode' => 'default',
              'field_name' => 'field_test',
            // Missing display_type.
            ],
            ],
          ], 'test.yml'
      );
  }

  /**
   * Tests valid flat format parsing.
   */
  public function testValidFlatFormat(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'id' => 'test_definition',
      'label' => 'Test Definition',
      'bundle_definitions' => [
      [
        'entity_type' => 'node',
        'bundle_id' => 'test_article',
        'label' => 'Test Article',
      ],
      ],
      'field_definitions' => [
      [
        'entity_type' => 'node',
        'bundle' => 'test_article',
        'field_name' => 'field_test',
        'field_type' => 'string',
        'label' => 'Test Field',
      ],
      ],
      'display_field_definitions' => [
      [
        'entity_type' => 'node',
        'bundle' => 'test_article',
        'display_type' => 'form',
        'mode' => 'default',
        'field_name' => 'field_test',
        'widget' => 'string_textfield',
      ],
      ],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests very large cardinality in flat format.
   */
  public function testLargeCardinality(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'bundle_definitions' => [
      [
        'entity_type' => 'node',
        'bundle_id' => 'article',
        'label' => 'Article',
      ],
      ],
      'field_definitions' => [
      [
        'entity_type' => 'node',
        'bundle' => 'article',
        'field_name' => 'field_unlimited',
        'field_type' => 'string',
        'cardinality' => -1,
      ],
      ],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests empty arrays in flat format.
   */
  public function testEmptyArrays(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'bundle_definitions' => [],
      'field_definitions' => [],
      'field_group_definitions' => [],
      'display_field_definitions' => [],

      'menu_definitions' => [],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests extension columns on bundles.
   */
  public function testExtensionColumnsOnBundles(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'bundle_definitions' => [
      [
        'entity_type' => 'node',
        'bundle_id' => 'article',
        'label' => 'Article',
        'pathauto_pattern' => '/blog/[node:title]',
        'auto_entitylabel_status' => 'enabled',
        'auto_entitylabel_pattern' => '[node:field_date] - [node:title]',
      ],
      ],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests field group definitions.
   */
  public function testFieldGroupDefinitions(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'bundle_definitions' => [
      [
        'entity_type' => 'node',
        'bundle_id' => 'article',
        'label' => 'Article',
      ],
      ],
      'field_group_definitions' => [
      [
        'entity_type' => 'node',
        'bundle' => 'article',
        'display_type' => 'form',
        'mode' => 'default',
        'group_name' => 'group_content',
        'label' => 'Content',
        'format_type' => 'fieldset',
      ],
      ],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests missing field group required keys.
   */
  public function testMissingFieldGroupKeys(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $this->expectException(ValidationException::class);
    $this->expectExceptionMessageMatches('/field_group_definitions.*group_name/');

    $factory->createFromYaml(
          [
            'bundle_definitions' => [
          [
            'entity_type' => 'node',
            'bundle_id' => 'article',
            'label' => 'Article',
          ],
            ],
            'field_group_definitions' => [
            [
              'entity_type' => 'node',
              'bundle' => 'article',
              'display_type' => 'form',
              'mode' => 'default',
            // Missing group_name.
            ],
            ],
          ], 'test.yml'
      );
  }

  /**
   * Tests multiple bundles across entity types.
   */
  public function testMultipleBundlesAcrossEntityTypes(): void {
    $factory = new DefinitionFactory($this->createEntityTypeManagerMock());

    $data = [
      'bundle_definitions' => [
      [
        'entity_type' => 'node',
        'bundle_id' => 'article',
        'label' => 'Article',
      ],
      [
        'entity_type' => 'node',
        'bundle_id' => 'page',
        'label' => 'Page',
      ],
      [
        'entity_type' => 'taxonomy_term',
        'bundle_id' => 'tags',
        'label' => 'Tags',
      ],
      ],
    ];

    $definition = $factory->createFromYaml($data, 'test.yml');
    $this->assertNotNull($definition);
  }

  /**
   * Tests dependency resolver with flat operations.
   */
  public function testDependencyResolverWithFlatOperations(): void {
    $entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
    $resolver = new DependencyResolver($entityTypeManager, $this->createExtensionManagerMock());

    $operations = [
      [
        'operation' => 'create_bundle',
        'entity_type' => 'node',
        'bundle_id' => 'article',
      ],
      [
        'operation' => 'create_field',
        'entity_type' => 'node',
        'bundle' => 'article',
        'field_name' => 'field_test',
        'field_type' => 'string',
      ],
    ];

    $sorted = $resolver->resolve($operations, FALSE);
    $this->assertIsArray($sorted);
    $this->assertCount(2, $sorted);
  }

}
