<?php

declare(strict_types=1);

namespace Drupal\Tests\acquia_dam\Kernel;

/**
 * Tests the media type resolver service.
 *
 * @group acquia_dam_kernel
 */
final class MediaTypeResolverTest extends AcquiaDamKernelTestBase {

  /**
   * Tests that standard asset format_types resolve to the correct media type.
   *
   * @dataProvider resolveMediaTypeDataProvider
   */
  public function testResolve(array $asset, string $expected_source_plugin_id): void {
    // Create all media types so the resolver has the full set to pick from.
    $this->createArchiveMediaType();
    $this->createAudioMediaType();
    $this->createDocumentMediaType();
    $this->createGenericMediaType();
    $this->createImageMediaType();
    $this->createPdfMediaType();
    $this->createSpinsetMediaType();
    $this->createVideoMediaType();
    $this->createMetadataTestMediaType();

    $sut = $this->container->get('acquia_dam.media_type_resolver');
    $resolved = $sut->resolve($asset);

    self::assertNotNull($resolved);
    self::assertEquals(
      $expected_source_plugin_id,
      $resolved->getSource()->getPluginDefinition()['id'],
    );
  }

  /**
   * Data provider for testResolve.
   */
  public static function resolveMediaTypeDataProvider(): \Generator {
    yield 'Audio format_type resolves to archive' => [
      ['file_properties' => ['format_type' => 'compressed_archive']],
      'archive',
    ];

    yield 'Audio format_type resolves to audio' => [
      ['file_properties' => ['format_type' => 'audio']],
      'audio',
    ];

    yield 'Office format_type resolves to documents' => [
      ['file_properties' => ['format_type' => 'office']],
      'documents',
    ];

    yield 'Generic binary format_type resolves to generic' => [
      ['file_properties' => ['format_type' => 'generic_binary']],
      'generic',
    ];

    yield 'Image format_type resolves to image' => [
      ['file_properties' => ['format_type' => 'image']],
      'image',
    ];

    yield 'PDF format_type resolves to pdf' => [
      ['file_properties' => ['format_type' => 'pdf']],
      'pdf',
    ];

    yield 'SpinSet format resolves to spinset' => [
      ['file_properties' => ['format' => 'SpinSet']],
      'spinset',
    ];

    yield 'Video format_type resolves to video' => [
      ['file_properties' => ['format_type' => 'video']],
      'video',
    ];

    yield 'Metadata field match resolves to metadata test type' => [
      [
        'file_properties' => [],
        'metadata' => ['fields' => ['assettype' => 'my value']],
      ],
      'metadataassettestmediasource',
    ];
  }

  /**
   * Tests that assets fall back to generic media type when no specific match.
   *
   * This includes assets with unknown format_types or
   * non-matching metadata fields.
   *
   * @dataProvider resolveGenericFallbackDataProvider
   */
  public function testResolveGenericFallback(array $asset, string $message): void {
    $this->createGenericMediaType();
    $this->createImageMediaType(['download_assets' => TRUE]);
    $this->createVideoMediaType();
    $this->createPdfMediaType();

    $sut = $this->container->get('acquia_dam.media_type_resolver');
    $resolved = $sut->resolve($asset);
    self::assertNotNull($resolved);
    self::assertEquals(
      'generic',
      $resolved->getSource()->getPluginDefinition()['id'],
      $message,
    );
  }

  /**
   * Data provider for testResolveGenericFallback.
   */
  public static function resolveGenericFallbackDataProvider(): \Generator {
    yield 'Unknown format_type falls back to generic' => [
      ['file_properties' => ['format_type' => 'generic_binary']],
      'Unknown format_type must fall back to generic media type.',
    ];

    yield 'Completely unknown format falls back to generic' => [
      ['file_properties' => ['format_type' => 'unknown_xyz']],
      'Completely unknown format must fall back to generic media type.',
    ];

    yield 'No matching format field falls back to generic' => [
      ['file_properties' => ['some_field' => 'pdf']],
      'Asset with non-matching format field must fall back to generic media type.',
    ];

    yield 'Metadata field present but no match falls back to generic' => [
      [
        'file_properties' => [],
        'metadata' => ['fields' => ['assettype' => 'not a match']],
      ],
      'Asset with non-matching metadata field must fall back to generic media type.',
    ];
  }

  /**
   * Tests that assets without file_properties return NULL.
   */
  public function testResolveReturnsNull(): void {
    $sut = $this->container->get('acquia_dam.media_type_resolver');
    $resolved = $sut->resolve([]);
    self::assertNull($resolved, 'Empty asset without file_properties must return NULL, not fall back to generic.');
  }

  /**
   * Tests resolving image format_type assets with download_assets enabled.
   *
   * SVG/TIFF assets have format_type = 'image' in the DAM API but their file
   * extensions are not in Drupal's default image field accepted extensions
   * (png gif jpg jpeg webp). Before the fix, these were incorrectly resolved
   * to the generic media type when download_assets was enabled.
   *
   * @dataProvider resolveImageWithDownloadAssetsDataProvider
   *
   * @see \Drupal\acquia_dam\MediaTypeResolver::resolve()
   */
  public function testResolveImageFormatTypeWithDownloadAssetsEnabled(
    array $asset,
    bool $download_assets,
    string $expected_source_plugin_id,
    string $message,
  ): void {
    $this->createGenericMediaType();
    $this->createImageMediaType([
      'download_assets' => $download_assets,
      'file_extensions' => 'png gif jpg jpeg webp, svg,tiff,.ai',
    ]);

    $sut = $this->container->get('acquia_dam.media_type_resolver');
    $resolved = $sut->resolve($asset);

    self::assertNotNull($resolved);
    self::assertEquals(
      $expected_source_plugin_id,
      $resolved->getSource()->getPluginDefinition()['id'],
      $message,
    );
  }

  /**
   * Data provider for testResolveImageFormatTypeWithDownloadAssetsEnabled.
   */
  public static function resolveImageWithDownloadAssetsDataProvider(): \Generator {
    $make_asset = static function (string $format, string $filename, string $external_id): array {
      return [
        'file_properties' => ['format' => $format, 'format_type' => 'image'],
        'filename' => $filename,
        'external_id' => $external_id,
        'embeds' => [
          'templated' => [
            'url' => "https://embed.widencdn.net/img/acms/$external_id/{{size}}px@{{scale}}x/$filename?q={{quality}}&x.template=y",
          ],
        ],
      ];
    };

    yield 'SVG with download_assets=TRUE resolves to image, not generic' => [
      $make_asset('SVG', 'globe.svg', 'hlpkpsrm9y'),
      TRUE,
      'image',
      'SVG (format_type=image, download_assets=TRUE) must resolve to image media type.',
    ];

    yield 'TIFF with download_assets=TRUE resolves to image, not generic' => [
      $make_asset('TIFF', 'photo.tiff', 'tiffextid1'),
      TRUE,
      'image',
      'TIFF (format_type=image, download_assets=TRUE) must resolve to image media type.',
    ];

    yield 'AI with download_assets=TRUE resolves to image, not generic' => [
      $make_asset('AI', 'logo.ai', 'aiextidabc'),
      TRUE,
      'image',
      'AI (format_type=image, download_assets=TRUE) must resolve to image media type.',
    ];

    yield 'PNG (standard extension) with download_assets=TRUE resolves to image' => [
      $make_asset('PNG', 'photo.png', 'pngextidabc'),
      TRUE,
      'image',
      'PNG (standard extension, download_assets=TRUE) must resolve to image media type.',
    ];

    yield 'JPG (standard extension) with download_assets=TRUE resolves to image' => [
      $make_asset('JPG', 'photo.jpg', 'jpgextidabc'),
      TRUE,
      'image',
      'JPG (standard extension, download_assets=TRUE) must resolve to image media type.',
    ];

    yield 'SVG with download_assets=FALSE (embed mode) resolves to image' => [
      $make_asset('SVG', 'globe.svg', 'hlpkpsrm9y'),
      FALSE,
      'image',
      'SVG (format_type=image, download_assets=FALSE) must resolve to image media type.',
    ];
  }

}
