<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Kernel\Service;

use Drupal\KernelTests\KernelTestBase;
use Drupal\visitors\Service\SocialNetworksService;

/**
 * Kernel tests for the SocialNetworksService.
 *
 * @group visitors
 * @coversDefaultClass \Drupal\visitors\Service\SocialNetworksService
 */
final class SocialNetworksServiceTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'visitors',
    'user',
  ];

  /**
   * The social networks service.
   *
   * @var \Drupal\visitors\Service\SocialNetworksService
   */
  private SocialNetworksService $socialNetworksService;

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

    $this->installConfig(['visitors']);
    $this->socialNetworksService = $this->container->get('visitors.social_networks');
  }

  /**
   * Tests the service is properly registered and injectable.
   *
   * @covers ::__construct
   */
  public function testServiceRegistration(): void {
    $this->assertInstanceOf(SocialNetworksService::class, $this->socialNetworksService);
  }

  /**
   * Tests basic configuration loading.
   */
  public function testConfigurationBasics(): void {
    // Test that configuration is loaded.
    $reflection = new \ReflectionClass($this->socialNetworksService);
    $method = $reflection->getMethod('getConfig');
    $method->setAccessible(TRUE);
    $config = $method->invoke($this->socialNetworksService);

    $this->assertIsArray($config);
    $this->assertNotEmpty($config);

    // Find Facebook in the configuration.
    $facebook = NULL;
    foreach ($config as $item) {
      if ($item['label'] === 'Facebook') {
        $facebook = $item;
        break;
      }
    }

    $this->assertNotNull($facebook, 'Facebook should be found in configuration');
    $this->assertIsArray($facebook['hosts']);
    $this->assertContains('facebook.com', $facebook['hosts']);
    $this->assertContains('fb.me', $facebook['hosts']);
    $this->assertContains('m.facebook.com', $facebook['hosts']);
  }

  /**
   * Tests matching Facebook hostnames.
   *
   * @covers ::match
   */
  public function testMatchFacebook(): void {
    $result = $this->socialNetworksService->match('facebook.com');
    $this->assertEquals('Facebook', $result);

    $result = $this->socialNetworksService->match('fb.me');
    $this->assertEquals('Facebook', $result);

    $result = $this->socialNetworksService->match('m.facebook.com');
    $this->assertEquals('Facebook', $result);

    $result = $this->socialNetworksService->match('l.facebook.com');
    $this->assertEquals('Facebook', $result);
  }

  /**
   * Tests matching Twitter hostnames.
   *
   * @covers ::match
   */
  public function testMatchTwitter(): void {
    $result = $this->socialNetworksService->match('twitter.com');
    $this->assertEquals('Twitter', $result);

    $result = $this->socialNetworksService->match('t.co');
    $this->assertEquals('Twitter', $result);

    $result = $this->socialNetworksService->match('x.com');
    $this->assertEquals('Twitter', $result);
  }

  /**
   * Tests matching Instagram hostnames.
   *
   * @covers ::match
   */
  public function testMatchInstagram(): void {
    $result = $this->socialNetworksService->match('instagram.com');
    $this->assertEquals('Instagram', $result);

    $result = $this->socialNetworksService->match('l.instagram.com');
    $this->assertEquals('Instagram', $result);
  }

  /**
   * Tests matching LinkedIn hostnames.
   *
   * @covers ::match
   */
  public function testMatchLinkedIn(): void {
    $result = $this->socialNetworksService->match('linkedin.com');
    $this->assertEquals('LinkedIn', $result);

    $result = $this->socialNetworksService->match('lnkd.in');
    $this->assertEquals('LinkedIn', $result);

    $result = $this->socialNetworksService->match('linkedin.android');
    $this->assertEquals('LinkedIn', $result);
  }

  /**
   * Tests matching YouTube hostnames.
   *
   * @covers ::match
   */
  public function testMatchYouTube(): void {
    $result = $this->socialNetworksService->match('youtube.com');
    $this->assertEquals('YouTube', $result);

    $result = $this->socialNetworksService->match('youtu.be');
    $this->assertEquals('YouTube', $result);
  }

  /**
   * Tests matching Pinterest hostnames.
   *
   * @covers ::match
   */
  public function testMatchPinterest(): void {
    $result = $this->socialNetworksService->match('pinterest.com');
    $this->assertEquals('Pinterest', $result);

    $result = $this->socialNetworksService->match('pinterest.ca');
    $this->assertEquals('Pinterest', $result);

    $result = $this->socialNetworksService->match('pinterest.co.uk');
    $this->assertEquals('Pinterest', $result);

    $result = $this->socialNetworksService->match('at.pinterest.com');
    $this->assertEquals('Pinterest', $result);
  }

  /**
   * Tests matching Reddit hostnames.
   *
   * @covers ::match
   */
  public function testMatchReddit(): void {
    $result = $this->socialNetworksService->match('reddit.com');
    $this->assertEquals('reddit', $result);

    $result = $this->socialNetworksService->match('np.reddit.com');
    $this->assertEquals('reddit', $result);

    $result = $this->socialNetworksService->match('pay.reddit.com');
    $this->assertEquals('reddit', $result);
  }

  /**
   * Tests matching Mastodon hostnames.
   *
   * @covers ::match
   */
  public function testMatchMastodon(): void {
    $result = $this->socialNetworksService->match('mastodon.social');
    $this->assertEquals('Mastodon', $result);

    $result = $this->socialNetworksService->match('mastodon.cloud');
    $this->assertEquals('Mastodon', $result);

    $result = $this->socialNetworksService->match('mastodon.technology');
    $this->assertEquals('Mastodon', $result);

    $result = $this->socialNetworksService->match('mastodon.xyz');
    $this->assertEquals('Mastodon', $result);
  }

  /**
   * Tests matching GitHub hostnames.
   *
   * @covers ::match
   */
  public function testMatchGitHub(): void {
    $result = $this->socialNetworksService->match('github.com');
    $this->assertEquals('GitHub', $result);
  }

  /**
   * Tests matching TikTok hostnames.
   *
   * @covers ::match
   */
  public function testMatchTikTok(): void {
    $result = $this->socialNetworksService->match('tiktok.com');
    $this->assertEquals('TikTok', $result);
  }

  /**
   * Tests matching Threads hostnames.
   *
   * @covers ::match
   */
  public function testMatchThreads(): void {
    $result = $this->socialNetworksService->match('threads.net');
    $this->assertEquals('Threads', $result);

    $result = $this->socialNetworksService->match('l.threads.net');
    $this->assertEquals('Threads', $result);
  }

  /**
   * Tests case-insensitive matching.
   *
   * @covers ::match
   */
  public function testCaseInsensitiveMatching(): void {
    $result = $this->socialNetworksService->match('FACEBOOK.COM');
    $this->assertEquals('Facebook', $result);

    $result = $this->socialNetworksService->match('Twitter.Com');
    $this->assertEquals('Twitter', $result);

    $result = $this->socialNetworksService->match('  INSTAGRAM.COM  ');
    $this->assertEquals('Instagram', $result);
  }

  /**
   * Tests matching with whitespace.
   *
   * @covers ::match
   */
  public function testMatchWithWhitespace(): void {
    $result = $this->socialNetworksService->match('  facebook.com  ');
    $this->assertEquals('Facebook', $result);

    $result = $this->socialNetworksService->match('  twitter.com  ');
    $this->assertEquals('Twitter', $result);
  }

  /**
   * Tests matching non-existent hostnames.
   *
   * @covers ::match
   */
  public function testMatchNonExistentHostnames(): void {
    $result = $this->socialNetworksService->match('nonexistent.com');
    $this->assertNull($result);

    $result = $this->socialNetworksService->match('chatgpt.com');
    $this->assertNull($result);

    $result = $this->socialNetworksService->match('google.com');
    $this->assertNull($result);
  }

  /**
   * Tests matching with empty hostname.
   *
   * @covers ::match
   */
  public function testMatchEmptyHostname(): void {
    $result = $this->socialNetworksService->match('');
    $this->assertNull($result);
  }

  /**
   * Tests service dependency injection in kernel environment.
   */
  public function testServiceDependencyInjection(): void {
    // Verify the service can be retrieved from the container.
    $service = $this->container->get('visitors.social_networks');
    $this->assertInstanceOf(SocialNetworksService::class, $service);

    // Verify it's the same instance.
    $this->assertSame($this->socialNetworksService, $service);
  }

  /**
   * Tests configuration caching.
   */
  public function testConfigurationCaching(): void {
    // First call should load from config.
    $result1 = $this->socialNetworksService->match('facebook.com');
    $this->assertEquals('Facebook', $result1);

    // Second call should use cached config.
    $result2 = $this->socialNetworksService->match('facebook.com');
    $this->assertEquals('Facebook', $result2);

    // Verify both results are the same.
    $this->assertEquals($result1, $result2);
  }

  /**
   * Tests matching with various social network types.
   */
  public function testMatchVariousSocialNetworks(): void {
    // Test professional networks.
    $result = $this->socialNetworksService->match('xing.com');
    $this->assertEquals('XING', $result);

    // Test video platforms.
    $result = $this->socialNetworksService->match('vimeo.com');
    $this->assertEquals('Vimeo', $result);

    // Test photo sharing.
    $result = $this->socialNetworksService->match('flickr.com');
    $this->assertEquals('Flickr', $result);

    // Test music platforms.
    $result = $this->socialNetworksService->match('soundcloud.com');
    $this->assertEquals('SoundCloud', $result);

    // Test question-answer platforms.
    $result = $this->socialNetworksService->match('stackoverflow.com');
    $this->assertEquals('StackOverflow', $result);
  }

}
