<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Kernel\Service;

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

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

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

  /**
   * The tracker service.
   *
   * @var \Drupal\visitors\Service\TrackerService
   */
  private TrackerService $trackerService;

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

    $this->installConfig(['visitors']);
    $this->installSchema('visitors', ['visitors_visit', 'visitors_event']);
    $this->trackerService = $this->container->get('visitors.tracker');
  }

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

  /**
   * Tests time since calculation for a new visitor.
   *
   * @covers ::getVisitId
   */
  public function testTimeSinceForNewVisitor(): void {
    $fields = [
      'visitor_id' => 'new_visitor_123',
      'entry_time' => 1000,
      'exit_time' => 1000,
      'total_time' => 0,
      'total_page_views' => 0,
      'total_events' => 0,
      'returning' => 0,
      'total_visits' => 1,
      'bot' => 0,
      'config_id' => 'test_config_123',
      'config_resolution' => '1920x1080',
      'config_pdf' => 1,
      'config_flash' => 0,
      'config_java' => 0,
      'config_quicktime' => 0,
      'config_realplayer' => 0,
      'config_windowsmedia' => 0,
      'config_silverlight' => 0,
      'config_cookie' => 1,
      'config_browser_engine' => 'WebKit',
      'config_browser_name' => 'CH',
      'config_browser_version' => '100.0',
      'config_client_type' => 'browser',
      'config_device_brand' => 'Apple',
      'config_device_model' => 'iPhone',
      'config_device_type' => 'smartphone',
      'config_os' => 'iOS',
      'config_os_version' => '15.0',
      'location_browser_lang' => 'en',
      'location_ip' => '127.0.0.1',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'location_region' => 'CA',
      'location_city' => 'San Francisco',
      'location_latitude' => 37.7749,
      'location_longitude' => -122.4194,
    ];

    $visit_id = $this->trackerService->getVisitId($fields, 1000);

    // Verify the visit was created.
    $this->assertIsInt($visit_id);
    $this->assertGreaterThan(0, $visit_id);

    // Check the database to verify time since fields were set to 0.
    $database = $this->container->get('database');
    $visit = $database->select('visitors_visit', 'vv')
      ->fields('vv', ['time_since_first', 'time_since_last', 'returning'])
      ->condition('vv.id', $visit_id)
      ->execute()
      ->fetchAssoc();

    $this->assertNotNull($visit);
    $this->assertEquals(0, $visit['time_since_first']);
    $this->assertEquals(0, $visit['time_since_last']);
    $this->assertEquals(0, $visit['returning']);
  }

  /**
   * Tests time since calculation for a returning visitor.
   *
   * @covers ::getVisitId
   */
  public function testTimeSinceForReturningVisitor(): void {
    $database = $this->container->get('database');

    // First, create an initial visit.
    $initial_fields = [
      'visitor_id' => 'returning_visitor_456',
      'entry_time' => 1000,
      'exit_time' => 1100,
      'total_time' => 100,
      'total_page_views' => 1,
      'total_events' => 1,
      'returning' => 0,
      'total_visits' => 1,
      'bot' => 0,
      'config_id' => 'test_config_456',
      'config_resolution' => '1920x1080',
      'config_pdf' => 1,
      'config_flash' => 0,
      'config_java' => 0,
      'config_quicktime' => 0,
      'config_realplayer' => 0,
      'config_windowsmedia' => 0,
      'config_silverlight' => 0,
      'config_cookie' => 1,
      'config_browser_engine' => 'WebKit',
      'config_browser_name' => 'CH',
      'config_browser_version' => '100.0',
      'config_client_type' => 'browser',
      'config_device_brand' => 'Apple',
      'config_device_model' => 'iPhone',
      'config_device_type' => 'smartphone',
      'config_os' => 'iOS',
      'config_os_version' => '15.0',
      'location_browser_lang' => 'en',
      'location_ip' => '127.0.0.1',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'location_region' => 'CA',
      'location_city' => 'San Francisco',
      'location_latitude' => 37.7749,
      'location_longitude' => -122.4194,
    ];

    $first_visit_id = $this->trackerService->getVisitId($initial_fields, 1000);

    // Now create a second visit for the same visitor (after session timeout)
    $returning_fields = [
      'visitor_id' => 'returning_visitor_456',
    // 2000 seconds later (after session timeout)
      'entry_time' => 3000,
      'exit_time' => 3000,
      'total_time' => 0,
      'total_page_views' => 0,
      'total_events' => 0,
      'returning' => 0,
      'total_visits' => 1,
      'bot' => 0,
      'config_id' => 'test_config_456',
      'config_resolution' => '1920x1080',
      'config_pdf' => 1,
      'config_flash' => 0,
      'config_java' => 0,
      'config_quicktime' => 0,
      'config_realplayer' => 0,
      'config_windowsmedia' => 0,
      'config_silverlight' => 0,
      'config_cookie' => 1,
      'config_browser_engine' => 'WebKit',
      'config_browser_name' => 'CH',
      'config_browser_version' => '100.0',
      'config_client_type' => 'browser',
      'config_device_brand' => 'Apple',
      'config_device_model' => 'iPhone',
      'config_device_type' => 'smartphone',
      'config_os' => 'iOS',
      'config_os_version' => '15.0',
      'location_browser_lang' => 'en',
      'location_ip' => '127.0.0.1',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'location_region' => 'CA',
      'location_city' => 'San Francisco',
      'location_latitude' => 37.7749,
      'location_longitude' => -122.4194,
    ];

    $second_visit_id = $this->trackerService->getVisitId($returning_fields, 3000);

    // Verify the second visit was created.
    $this->assertIsInt($second_visit_id);
    $this->assertGreaterThan(0, $second_visit_id);

    // Check the database to verify time since fields were calculated correctly.
    $second_visit = $database->select('visitors_visit', 'vv')
      ->fields('vv', ['time_since_first', 'time_since_last', 'returning', 'total_visits'])
      ->condition('vv.id', $second_visit_id)
      ->execute()
      ->fetchAssoc();

    $this->assertNotNull($second_visit);
    $this->assertEquals(1, $second_visit['returning']);
    $this->assertEquals(2, $second_visit['total_visits']);

    // time_since_last should be 3000 - 1100 = 1900 seconds.
    $this->assertEquals(1900, $second_visit['time_since_last']);

    // time_since_first should be 0 + (3000 - 1000) = 2000 seconds
    // (since first visit had 0)
    $this->assertEquals(2000, $second_visit['time_since_first']);

    // Verify the first visit still has the correct values.
    $first_visit = $database->select('visitors_visit', 'vv')
      ->fields('vv', ['time_since_first', 'time_since_last', 'returning', 'total_visits'])
      ->condition('vv.id', $first_visit_id)
      ->execute()
      ->fetchAssoc();

    $this->assertNotNull($first_visit);
    $this->assertEquals(0, $first_visit['returning']);
    $this->assertEquals(1, $first_visit['total_visits']);
    $this->assertEquals(0, $first_visit['time_since_first']);
    $this->assertEquals(0, $first_visit['time_since_last']);
  }

  /**
   * Tests time since calculation for multiple returning visits.
   *
   * @covers ::getVisitId
   */
  public function testTimeSinceForMultipleReturningVisits(): void {
    $database = $this->container->get('database');

    // Create first visit.
    $first_fields = [
      'visitor_id' => 'multi_visitor_789',
      'entry_time' => 1000,
      'exit_time' => 1100,
      'total_time' => 100,
      'total_page_views' => 1,
      'total_events' => 1,
      'returning' => 0,
      'total_visits' => 1,
      'bot' => 0,
      'config_id' => 'test_config_789',
      'config_resolution' => '1920x1080',
      'config_pdf' => 1,
      'config_flash' => 0,
      'config_java' => 0,
      'config_quicktime' => 0,
      'config_realplayer' => 0,
      'config_windowsmedia' => 0,
      'config_silverlight' => 0,
      'config_cookie' => 1,
      'config_browser_engine' => 'WebKit',
      'config_browser_name' => 'CH',
      'config_browser_version' => '100.0',
      'config_client_type' => 'browser',
      'config_device_brand' => 'Apple',
      'config_device_model' => 'iPhone',
      'config_device_type' => 'smartphone',
      'config_os' => 'iOS',
      'config_os_version' => '15.0',
      'location_browser_lang' => 'en',
      'location_ip' => '127.0.0.1',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'location_region' => 'CA',
      'location_city' => 'San Francisco',
      'location_latitude' => 37.7749,
      'location_longitude' => -122.4194,
    ];

    $first_visit_id = $this->trackerService->getVisitId($first_fields, 1000);

    // Create second visit (after session timeout)
    $second_fields = $first_fields;
    // 2000 seconds after first visit
    $second_fields['entry_time'] = 3000;
    $second_fields['exit_time'] = 3000;
    $second_fields['total_time'] = 0;
    $second_fields['total_page_views'] = 0;
    $second_fields['total_events'] = 0;

    $second_visit_id = $this->trackerService->getVisitId($second_fields, 3000);

    // Create third visit (after session timeout)
    $third_fields = $first_fields;
    // 2000 seconds after second visit
    $third_fields['entry_time'] = 5000;
    $third_fields['exit_time'] = 5000;
    $third_fields['total_time'] = 0;
    $third_fields['total_page_views'] = 0;
    $third_fields['total_events'] = 0;

    $third_visit_id = $this->trackerService->getVisitId($third_fields, 5000);

    // Verify the third visit has correct time since values.
    $third_visit = $database->select('visitors_visit', 'vv')
      ->fields('vv', ['time_since_first', 'time_since_last', 'returning', 'total_visits'])
      ->condition('vv.id', $third_visit_id)
      ->execute()
      ->fetchAssoc();

    $this->assertNotNull($third_visit);
    $this->assertEquals(1, $third_visit['returning']);
    $this->assertEquals(3, $third_visit['total_visits']);

    // time_since_last should be 5000 - 3000 = 2000 seconds.
    $this->assertEquals(2000, $third_visit['time_since_last']);

    // time_since_first should be 2000 + (5000 - 3000) = 4000 seconds
    // (2000 from second visit + 2000 from third visit)
    $this->assertEquals(4000, $third_visit['time_since_first']);
  }

}
