<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Unit\Service;

use Drupal\Tests\UnitTestCase;
use Drupal\visitors\Service\UpgradeService;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Tests the CookieService class.
 *
 * @coversDefaultClass \Drupal\visitors\Service\UpgradeService
 * @uses \Drupal\visitors\Service\UpgradeService
 * @uses \Drupal\visitors\Helper\VisitorsUrl
 * @group visitors
 */
class UpgradeServiceTest extends UnitTestCase {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $database;

  /**
   * The visitors tracker.
   *
   * @var \Drupal\visitors\VisitorsTrackerInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $tracker;

  /**
   * The upgrade service.
   *
   * @var \Drupal\visitors\Service\UpgradeService
   */
  protected $service;

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

    $container = new ContainerBuilder();

    $this->database = $this->createMock('Drupal\Core\Database\Connection');
    $this->tracker = $this->createMock('Drupal\visitors\VisitorsTrackerInterface');

    $container->set('database', $this->database);
    $container->set('visitors.tracker', $this->tracker);

    \Drupal::setContainer($container);

    $this->service = new UpgradeService($this->database, $this->tracker);
  }

  /**
   * Tests the construct method.
   *
   * @covers ::__construct
   */
  public function testConstruct() {
    $counter = new UpgradeService($this->database, $this->tracker);
    $this->assertInstanceOf(UpgradeService::class, $counter);
  }

  /**
   * Tests getTotal method.
   *
   * @covers ::getTotal
   */
  public function testGetTotal() {

    $statement = $this->createMock('Drupal\Core\Database\StatementInterface');
    $statement->expects($this->once())
      ->method('fetchField')
      ->willReturn(10);
    $select = $this->createMock('Drupal\Core\Database\Query\SelectInterface');
    $select->expects($this->once())
      ->method('countQuery')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('fields')
      ->with('v')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('execute')
      ->willReturn($statement);
    $this->database->expects($this->once())
      ->method('select')
      ->with('visitors', 'v')
      ->willReturn($select);

    $this->assertEquals(10, $this->service->getTotal());
  }

  /**
   * Tests upgradeRow method.
   *
   * @covers ::upgradeRow
   * @covers ::deleteVisitorsRow
   * @covers ::doVisitRecord
   * @covers ::doLogRecord
   */
  public function testUpgradeRow() {
    $row = [
      'visitors_uid' => '1',
      'bot' => 0,
      'config_browser_engine' => 'BL',
      'config_browser_name' => 'CH',
      'config_browser_version' => '1.0',
      'config_client_type' => 'DESKTOP',
      'config_cookie' => '1',
      'config_device_brand' => 'DELL',
      'config_device_model' => 'XPS',
      'config_device_type' => 'DESKTOP',
      'config_flash' => '1',
      'config_java' => '1',
      'config_os_version' => '1.0',
      'config_os' => 'WIN',
      'config_pdf' => '1',
      'config_quicktime' => '1',
      'config_realplayer' => '1',
      'config_resolution' => '1024x768',
      'config_silverlight' => '1',
      'config_windowsmedia' => '1',
      'language' => 'en',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'pf_dom_complete' => 1,
      'pf_dom_processing' => 1,
      'pf_network' => 1,
      'pf_on_load' => 1,
      'pf_server' => 1,
      'pf_total' => 6,
      'pf_transfer' => 1,
      'route' => 'entity.node.canonical',
      'server' => 'localhost',
      'visitor_id' => '123voh',
      'visitor_localtime' => 456,
      'visitors_date_time' => 123456,
      'visitors_id' => 1,
      'visitors_ip' => '127.0.0.1',
      'visitors_path' => '/node/1',
      'visitors_referer' => 'http://example.com',
      'visitors_title' => 'Title',
      'visitors_url' => 'http://example.com',
    ];

    $visit = [
      'uid' => 1,
      'location_browser_lang' => 'en',
      'localtime' => 456,
      'config_browser_engine' => 'BL',
      'config_browser_name' => 'CH',
      'config_browser_version' => '1.0',
      'config_client_type' => 'DESKTOP',
      'config_device_brand' => 'DELL',
      'config_device_model' => 'XPS',
      'config_device_type' => 'DESKTOP',
      'config_os' => 'WIN',
      'config_os_version' => '1.0',
      'bot' => 0,
      'config_resolution' => '1024x768',
      'config_pdf' => '1',
      'config_flash' => '1',
      'config_java' => '1',
      'config_quicktime' => '1',
      'config_realplayer' => '1',
      'config_windowsmedia' => '1',
      'config_silverlight' => '1',
      'config_cookie' => '1',
      'location_continent' => 'NA',
      'location_country' => 'US',
      'location_region' => NULL,
      'location_city' => NULL,
      'location_latitude' => NULL,
      'location_longitude' => NULL,
      'visitor_id' => '123voh',
      'total_time' => 0,
      'page_count' => 0,
      'returning' => 0,
      'visit_count' => 0,
      'entry_time' => 123456,
      'exit_time' => 123456,
      'location_ip' => '127.0.0.1',

    ];

    $log = [
      'uid' => '1',
      'url' => 'example.com',
      'url_prefix' => 0,
      'title' => 'Title',
      'referrer_url' => 'http://example.com',
      'path' => '/node/1',
      'route' => 'entity.node.canonical',
      'server' => 'localhost',
      'pf_network' => 1,
      'pf_server' => 1,
      'pf_transfer' => 1,
      'pf_dom_processing' => 1,
      'pf_dom_complete' => 1,
      'pf_on_load' => 1,
      'pf_total' => 6,
      'created' => 123456,
      'visit_id' => 1,
    ];

    $this->tracker->expects($this->once())
      ->method('getVisitId')
      ->with($visit, 123456)
      ->willReturn(1);

    $this->tracker->expects($this->once())
      ->method('writeLog')
      ->with($log)
      ->willReturn(1);

    $this->tracker->expects($this->once())
      ->method('updateVisit')
      ->with(1, 1, 123456, 1);

    $statement = $this->createMock('Drupal\Core\Database\StatementInterface');
    $delete = $this->createMock('Drupal\Core\Database\Query\Delete');
    $delete->expects($this->once())
      ->method('condition')
      ->with('visitors_id', 1)
      ->willReturnSelf();
    $delete->expects($this->once())
      ->method('execute')
      ->willReturn($statement);
    $this->database->expects($this->once())
      ->method('delete')
      ->with('visitors')
      ->willReturn($delete);

    $this->service->upgradeRow($row);
  }

  /**
   * Tests getVisitorsRows method.
   *
   * @covers ::getVisitorsRows
   */
  public function testGetVisitorsRows() {
    $statement = $this->createMock('Drupal\Core\Database\StatementInterface');
    $statement->expects($this->once())
      ->method('fetchAll')
      ->willReturn([['visitors_id' => 1]]);
    $select = $this->createMock('Drupal\Core\Database\Query\SelectInterface');
    $select->expects($this->once())
      ->method('fields')
      ->with('v')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('orderBy')
      ->with('v.visitors_date_time', 'ASC')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('range')
      ->with(0, 50)
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('execute')
      ->willReturn($statement);
    $this->database->expects($this->once())
      ->method('select')
      ->with('visitors', 'v')
      ->willReturn($select);

    $this->assertEquals([['visitors_id' => 1]], $this->service->getVisitorsRows(50));
  }

}
