<?php

declare(strict_types=1);

namespace Drupal\KernelTests\Core\Theme;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\MarkupTrait;
use Drupal\Core\GeneratedLink;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\KernelTests\KernelTestBase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

/**
 * Tests Twig with MarkupInterface objects.
 */
#[Group('Theme')]
#[RunTestsInSeparateProcesses]
class TwigMarkupInterfaceTest extends KernelTestBase {

  /**
 * Tests markup interface empty.
 */
  #[DataProvider('providerTestMarkupInterfaceEmpty')]
  public function testMarkupInterfaceEmpty($expected, $variable): void {
    $this->assertSame($expected, (string) $this->renderObjectWithTwig($variable));
  }

  /**
   * Provide test examples.
   */
  public static function providerTestMarkupInterfaceEmpty(): array {
    return [
      // The first argument to \Drupal\Core\StringTranslation\TranslatableMarkup
      // is not supposed to be an empty string.
      // phpcs:ignore Drupal.Semantics.FunctionT.EmptyString
      'empty TranslatableMarkup' => ['', new TranslatableMarkup('')],
      'non-empty TranslatableMarkup' => [
        '<span>test</span>',
        new TranslatableMarkup('test'),
      ],
      'empty FormattableMarkup' => [
        '',
        new FormattableMarkup('', ['@foo' => 'bar']),
      ],
      'non-empty FormattableMarkup' => [
        '<span>bar</span>',
        new FormattableMarkup('@foo', ['@foo' => 'bar']),
      ],
      'non-empty Markup' => ['<span>test</span>', Markup::create('test')],
      'empty GeneratedLink' => ['', new GeneratedLink()],
      'non-empty GeneratedLink' => [
        '<span><a hef="http://www.example.com">test</a></span>',
        (new GeneratedLink())->setGeneratedLink('<a hef="http://www.example.com">test</a>'),
      ],
      // Test objects that do not implement \Countable.
      'empty SafeMarkupTestMarkup' => ['', SafeMarkupTestMarkup::create('')],
      'non-empty SafeMarkupTestMarkup' => [
        '<span>test</span>',
        SafeMarkupTestMarkup::create('test'),
      ],
    ];
  }

  /**
   * Tests behavior if a string is translated to become an empty string.
   */
  public function testEmptyTranslation(): void {
    $settings = Settings::getAll();
    $settings['locale_custom_strings_en'] = ['' => ['test' => '']];
    // Recreate the settings static.
    new Settings($settings);

    $variable = new TranslatableMarkup('test');
    $this->assertEquals('', (string) $this->renderObjectWithTwig($variable));

    $variable = new TranslatableMarkup('test', [], ['langcode' => 'de']);
    $this->assertEquals('<span>test</span>', (string) $this->renderObjectWithTwig($variable));
  }

  /**
   * Renders a variable using a Twig inline template.
   *
   * @return \Drupal\Component\Render\MarkupInterface
   *   The rendered HTML.
   */
  protected function renderObjectWithTwig($variable) {
    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');
    $context = new RenderContext();
    return $renderer->executeInRenderContext($context, function () use ($renderer, $variable) {
      $elements = [
        '#type' => 'inline_template',
        '#template' => '{%- if variable is not empty -%}<span>{{ variable }}</span>{%- endif -%}',
        '#context' => ['variable' => $variable],
      ];
      return $renderer->render($elements);
    });
  }

}

/**
 * Implements MarkupInterface without implementing \Countable.
 */
class SafeMarkupTestMarkup implements MarkupInterface {
  use MarkupTrait;

  /**
   * Overrides MarkupTrait::create() to allow creation with empty strings.
   */
  public static function create($string): static {
    $object = new static();
    $object->string = $string;
    return $object;
  }

}
