<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Unit\Commands;

use Drupal\Tests\UnitTestCase;
use Drupal\visitors\Commands\VisitorsCommands;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Tests Visitors Drush commands.
 *
 * @group visitors
 * @coversDefaultClass \Drupal\visitors\Commands\VisitorsCommands
 */
class VisitorsCommandsTest 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 visitors upgrade.
   *
   * @var \Drupal\visitors\VisitorsUpgradeInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $upgrade;

  /**
   * The visitors commands.
   *
   * @var \Drupal\visitors\Commands\VisitorsCommands
   */
  protected $command;

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

    $container = new ContainerBuilder();

    $string_translation = $this->createMock('Drupal\Core\StringTranslation\TranslationInterface');
    $container->set('string_translation', $string_translation);

    $this->database = $this->createMock('Drupal\Core\Database\Connection');
    $container->set('database', $this->database);

    $this->tracker = $this->createMock('Drupal\visitors\VisitorsTrackerInterface');
    $container->set('visitors.tracker', $this->tracker);

    $this->upgrade = $this->createMock('Drupal\visitors\VisitorsUpgradeInterface');
    $container->set('visitors.upgrade', $this->upgrade);

    \Drupal::setContainer($container);

    $this->command = new VisitorsCommands($this->database, $this->tracker, $this->upgrade);
  }

  /**
   * Tests constructor.
   *
   * @covers ::__construct
   */
  public function testConstructor(): void {
    $command = new VisitorsCommands($this->database, $this->tracker, $this->upgrade);
    $this->assertInstanceOf(VisitorsCommands::class, $command);
  }

  /**
   * Tests Upgrade method.
   *
   * @covers ::upgrade
   * @covers ::doLog
   * @covers ::getVisitorsRow
   * @covers ::getTotal
   */
  public function testUpgrade(): void {
    $statement = $this->createMock('Drupal\Core\Database\StatementInterface');
    $statement->expects($this->once())
      ->method('fetchField')
      ->willReturn(1);
    $select = $this->createMock('Drupal\Core\Database\Query\SelectInterface');
    $select->expects($this->once())
      ->method('fields')
      ->with('v')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('isNotNull')
      ->with('v.visitor_id')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('countQuery')
      ->willReturnSelf();
    $select->expects($this->once())
      ->method('execute')
      ->willReturn($statement);

    $this->database->expects($this->once())
      ->method('select')
      ->with('visitors', 'v')
      ->willReturn($select);

    $this->upgrade->expects($this->once())
      ->method('getVisitorsRows')
      ->with(10000)
      ->willReturn([
        ['visitors_id' => 1, 'uid' => 1, 'visitors_date_time' => 1234567890, 'visitor_id' => 'drupal is awesome'],
      ]);

    $this->upgrade->expects($this->once())
      ->method('doVisitRecord')
      ->with(['visitors_id' => 1, 'uid' => 1, 'visitors_date_time' => 1234567890, 'visitor_id' => 'drupal is awesome'])
      ->willReturn(['uid' => 1]);
    $this->upgrade->expects($this->once())
      ->method('doLogRecord')
      ->with(['visitors_id' => 1, 'uid' => 1, 'visitors_date_time' => 1234567890, 'visitor_id' => 'drupal is awesome'])
      ->willReturn(['uid' => 1]);
    $this->tracker->expects($this->once())
      ->method('getVisitId')
      ->with(['uid' => 1], 1234567890)
      ->willReturn(1);
    $this->tracker->expects($this->once())
      ->method('writeEvent')
      ->with([
        'uid' => 1,
        'visit_id' => 1,
      ])
      ->willReturn(1);
    $this->tracker->expects($this->once())
      ->method('updateVisit')
      ->with(1, 1, 1234567890, 1);

    $this->upgrade->expects($this->once())
      ->method('deleteVisitorsRow')
      ->with(1);

    $this->command->upgrade();

  }

}
