<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Unit\Service;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Tests\UnitTestCase;
use Drupal\visitors\Service\SpamService;

/**
 * Tests the SpamService.
 *
 * @coversDefaultClass \Drupal\visitors\Service\SpamService
 * @group visitors
 */
class SpamServiceTest extends UnitTestCase {

  /**
   * The config factory mock.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  private ConfigFactoryInterface $configFactory;

  /**
   * The spam config mock.
   *
   * @var \Drupal\Core\Config\ImmutableConfig|\PHPUnit\Framework\MockObject\MockObject
   */
  private ImmutableConfig $spamConfig;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    $this->spamConfig = $this->createMock(ImmutableConfig::class);
    $this->configFactory = $this->createMock(ConfigFactoryInterface::class);
    $this->configFactory->method('get')
      ->with('visitors.spam')
      ->willReturn($this->spamConfig);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithSpam(): void {
    $spam_sites = ['example.com', 'spam-site.org'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);

    $result = $spam_service->match('example.com');

    $this->assertTrue($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithNonSpamUrl(): void {
    $spam_sites = ['example.com', 'spam-site.org'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('legitimate-site.com');

    $this->assertFalse($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithWwwPrefix(): void {
    $spam_sites = ['example.com'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('www.example.com');

    $this->assertTrue($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithSubdomain(): void {
    $spam_sites = ['example.com'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('sub.example.com');

    $this->assertTrue($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithPort(): void {
    $spam_sites = ['example.com'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('example.com');

    $this->assertTrue($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithInvalidUrl(): void {
    $spam_sites = ['example.com'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('not-a-valid-url');

    $this->assertFalse($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithEmptySpamSites(): void {
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn([]);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('example.com');

    $this->assertFalse($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithNullSpamSites(): void {
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn(NULL);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('example.com');

    $this->assertFalse($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithComplexUrl(): void {
    $spam_sites = ['spam-site.org'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('www.spam-site.org');

    $this->assertTrue($result);
  }

  /**
   * @covers ::match
   */
  public function testMatchWithCaseInsensitive(): void {
    $spam_sites = ['EXAMPLE.COM'];
    $this->spamConfig->method('get')
      ->with('sites')
      ->willReturn($spam_sites);

    $spam_service = new SpamService($this->configFactory);
    $result = $spam_service->match('Example.com');

    $this->assertTrue($result);
  }

}
