<?php

declare(strict_types=1);

namespace Drupal\Tests\native_observability\Unit\Service;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\native_observability\Service\RequestLogExclusionRepository;
use Drupal\native_observability\Service\RequestLogExclusionRuleNormalizer;
use PHPUnit\Framework\Attributes\CoversClass;

/**
 * Tests repository caching behavior for exclusion rules.
 */
#[CoversClass(RequestLogExclusionRepository::class)]
final class RequestLogExclusionRepositoryTest extends UnitTestCase {

  /**
   * Tests that cached normalized rules avoid DB access.
   */
  public function testCacheHitAvoidsDatabaseLookup(): void {
    $cache = $this->createMock(CacheBackendInterface::class);
    $cache->expects($this->once())
      ->method('get')
      ->with(RequestLogExclusionRepository::CACHE_ID)
      ->willReturn((object) [
        'data' => [['id' => 1, 'enabled' => TRUE]],
      ]);

    $database = $this->createMock(Connection::class);
    $database->expects($this->never())
      ->method('select');

    $repository = new RequestLogExclusionRepository(
      $database,
      $cache,
      $this->createMock(CacheTagsInvalidatorInterface::class),
      new RequestLogExclusionRuleNormalizer(),
    );

    $this->assertSame([['id' => 1, 'enabled' => TRUE]], $repository->loadNormalizedEnabledRules());
    $this->assertSame([['id' => 1, 'enabled' => TRUE]], $repository->loadNormalizedEnabledRules());
  }

  /**
   * Tests that cache invalidation resets runtime state.
   */
  public function testInvalidateRuntimeCacheClearsMemoizedState(): void {
    $cache = $this->createMock(CacheBackendInterface::class);
    $cache->method('get')
      ->willReturn(FALSE);
    $cache->expects($this->once())
      ->method('set');

    $invalidator = $this->createMock(CacheTagsInvalidatorInterface::class);
    $invalidator->expects($this->once())
      ->method('invalidateTags')
      ->with([RequestLogExclusionRepository::CACHE_TAG]);

    $select = $this->createMock(SelectInterface::class);
    $select->method('fields')->willReturnSelf();
    $select->method('condition')->willReturnSelf();
    $select->method('orderBy')->willReturnSelf();
    $select->method('execute')->willReturn(new class {

      /**
       * Returns rows for the fake select execution.
       */
      public function fetchAll($fetch_style = NULL) {
        return [
          [
            'id' => 9,
            'label' => 'Rule',
            'enabled' => 1,
            'method' => 'GET',
            'path_match_type' => 'exact',
            'path_pattern' => '/foo/bar',
            'query_conditions' => '[]',
          ],
        ];
      }

    });

    $database = $this->createMock(Connection::class);
    $database->expects($this->once())
      ->method('select')
      ->willReturn($select);

    $repository = new RequestLogExclusionRepository(
      $database,
      $cache,
      $invalidator,
      new RequestLogExclusionRuleNormalizer(),
    );

    $repository->loadNormalizedEnabledRules();
    $repository->invalidateRuntimeCache();
  }

}
