<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Kernel\Plugin\views\field;

use Drupal\Core\Database\Connection;
use Drupal\KernelTests\KernelTestBase;
use Drupal\views\ResultRow;
use Drupal\visitors\Plugin\views\field\NumberRange;

/**
 * Kernel tests for NumberRange views field plugin.
 *
 * @group visitors
 * @coversDefaultClass \Drupal\visitors\Plugin\views\field\NumberRange
 */
class NumberRangeTest extends KernelTestBase {

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

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

  /**
   * The field plugin instance.
   *
   * @var \Drupal\visitors\Plugin\views\field\NumberRange
   */
  protected NumberRange $field;

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

    // Install required schemas.
    $this->installSchema('visitors', ['visitors_visit', 'visitors_event']);

    // Create the field plugin.
    $this->field = $this->createFieldPlugin();

    // Set default options to prevent undefined array key warnings.
    $this->field->options = [
      'pluralize' => FALSE,
      'singular_label' => '1 item',
      'plural_label' => '@count items',
      'ranges' => "0\n1\n2\n3\n4\n5\n6-7\n8-10\n11-14\n15-20\n21+",
      'time_format' => FALSE,
    ];
  }

  /**
   * Creates a field plugin instance for testing.
   */
  protected function createFieldPlugin(): NumberRange {
    $configuration = [
      'table' => 'visitors_visit',
      'field' => 'total_page_views',
    ];
    $plugin_id = 'visitors_number_range';
    $plugin_definition = [];
    $field = NumberRange::create($this->container, $configuration, $plugin_id, $plugin_definition);

    // Set up the field properties directly.
    $field->tableAlias = 'vv';
    $field->realField = 'total_page_views';

    return $field;
  }

  /**
   * Tests the field plugin with default options.
   *
   * @covers ::render
   */
  public function testFieldPluginWithDefaultOptions(): void {
    $this->field->options['ranges'] = "0\n1\n2\n3\n4\n5\n6-7\n8-10\n11-14\n15-20\n21+";

    // Create a result row with the field value.
    $result_row = new ResultRow();
    $result_row->vv_total_page_views__range = '2';

    $this->field->field_alias = 'vv_total_page_views__range';

    $result = $this->field->render($result_row);

    $this->assertEquals('2', $result);
  }

  /**
   * Tests the field plugin with time format enabled.
   *
   * @covers ::render
   */
  public function testFieldPluginWithTimeFormat(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "60\n300\n1800\n3600";

    $result_row = new ResultRow();
    $result_row->vv_total_page_views_range = '300';

    $this->field->field_alias = 'vv_total_page_views_range';

    $result = $this->field->render($result_row);

    $this->assertEquals('5 minutes', $result);
  }

  /**
   * Tests the field plugin with pluralization enabled.
   *
   * @covers ::render
   */
  public function testFieldPluginWithPluralization(): void {
    $this->field->options['pluralize'] = TRUE;
    $this->field->options['singular_label'] = '1 page view';
    $this->field->options['plural_label'] = '@count page views';

    $result_row = new ResultRow();
    $result_row->vv_total_page_views_range = '3';

    $this->field->field_alias = 'vv_total_page_views_range';

    $result = $this->field->render($result_row);

    $this->assertEquals('3 page views', $result);
  }

  /**
   * Tests the field plugin with singular value.
   *
   * @covers ::render
   */
  public function testFieldPluginWithSingularValue(): void {
    $this->field->options['pluralize'] = TRUE;
    $this->field->options['singular_label'] = '1 page view';
    $this->field->options['plural_label'] = '@count page views';

    $result_row = new ResultRow();
    $result_row->vv_total_page_views_range = '1';

    $this->field->field_alias = 'vv_total_page_views_range';

    $result = $this->field->render($result_row);

    $this->assertEquals('1 page view', $result);
  }

  /**
   * Tests the field plugin with time range format.
   *
   * @covers ::formatTimeRange
   */
  public function testFieldPluginWithTimeRangeFormat(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "60-120\n300-600\n1800-3600";

    $result_row = new ResultRow();
    $result_row->vv_total_page_views_range = '60-120';

    $this->field->field_alias = 'vv_total_page_views_range';

    $result = $this->field->render($result_row);

    $this->assertEquals('1-2 minutes', $result);
  }

  /**
   * Tests time range format where start and end are less than 1 unit apart.
   *
   * @covers ::formatTimeRange
   */
  public function testFieldPluginWithTimeRangeFormatLessThanOneUnitApart(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "0-60\n0-3600\n0-86400";

    $test_cases = [
     ['index' => 0, 'expected' => '1 minute'],
     ['index' => 1, 'expected' => '1 hour'],
     ['index' => 2, 'expected' => '1 day'],
    ];

    foreach ($test_cases as $test_case) {
      $result_row = new ResultRow();
      $result_row->vv_total_page_views__range = (string) $test_case['index'];

      $this->field->field_alias = 'vv_total_page_views__range';

      $result = $this->field->render($result_row);

      $this->assertEquals($test_case['expected'], $result);
    }
  }

  /**
   * Tests time range format where start and end are exactly 1 unit apart.
   *
   * @covers ::formatTimeRange
   */
  public function testFieldPluginWithTimeRangeFormatExactlyOneUnitApart(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "60-120\n3600-7200\n86400-172800";

    $test_cases = [
      ['index' => 0, 'expected' => '1-2 minutes'],
      ['index' => 1, 'expected' => '1-2 hours'],
      ['index' => 2, 'expected' => '1-2 days'],
    ];

    foreach ($test_cases as $test_case) {
      $result_row = new ResultRow();
      $result_row->vv_total_page_views__range = (string) $test_case['index'];

      $this->field->field_alias = 'vv_total_page_views__range';

      $result = $this->field->render($result_row);

      $this->assertEquals($test_case['expected'], $result);
    }
  }

  /**
   * Tests time range format where start and end are more than 1 unit apart.
   *
   * @covers ::formatTimeRange
   */
  public function testFieldPluginWithTimeRangeFormatMoreThanOneUnitApart(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "60-180\n3600-10800\n86400-259200";

    $test_cases = [
      ['index' => 0, 'expected' => '1-3 minutes'],
      ['index' => 1, 'expected' => '1-3 hours'],
      ['index' => 2, 'expected' => '1-3 days'],
    ];

    foreach ($test_cases as $test_case) {
      $result_row = new ResultRow();
      $result_row->vv_total_page_views__range = (string) $test_case['index'];

      $this->field->field_alias = 'vv_total_page_views__range';

      $result = $this->field->render($result_row);

      $this->assertEquals($test_case['expected'], $result);
    }
  }

  /**
   * Tests the field plugin with time plus format.
   *
   * @covers ::formatTimeRange
   */
  public function testFieldPluginWithTimePlusFormat(): void {
    $this->field->options['time_format'] = TRUE;
    $this->field->options['ranges'] = "3600+\n86400+";

    $result_row = new ResultRow();
    $result_row->vv_total_page_views_range = '3600+';

    $this->field->field_alias = 'vv_total_page_views_range';

    $result = $this->field->render($result_row);

    $this->assertEquals('1+ hour', $result);
  }

  /**
   * Tests the field plugin with various time units.
   *
   * @covers ::formatSeconds
   */
  public function testFieldPluginWithVariousTimeUnits(): void {
    $this->field->options['time_format'] = TRUE;

    $test_cases = [
      ['input' => '0', 'expected' => '0 seconds'],
      ['input' => '1', 'expected' => '1 second'],
      ['input' => '30', 'expected' => '30 seconds'],
      ['input' => '60', 'expected' => '1 minute'],
      ['input' => '90', 'expected' => '1.5 minutes'],
      ['input' => '3600', 'expected' => '1 hour'],
      ['input' => '7200', 'expected' => '2 hours'],
      ['input' => '86400', 'expected' => '1 day'],
      ['input' => '172800', 'expected' => '2 days'],
      ['input' => '604800', 'expected' => '1 week'],
      ['input' => '1209600', 'expected' => '2 weeks'],
      ['input' => '2592000', 'expected' => '1 month'],
      ['input' => '5184000', 'expected' => '2 months'],
      ['input' => '31536000', 'expected' => '1 year'],
      ['input' => '63072000', 'expected' => '2 years'],
    ];

    foreach ($test_cases as $test_case) {
      $result_row = new ResultRow();
      $result_row->vv_total_page_views_range = $test_case['input'];

      $this->field->field_alias = 'vv_total_page_views_range';

      $result = $this->field->render($result_row);

      $this->assertEquals($test_case['expected'], $result);
    }
  }

  /**
   * Tests the field plugin with range labels.
   *
   * @covers ::getRangeLabel
   */
  public function testFieldPluginWithRangeLabels(): void {
    $this->field->options['ranges'] = "0\n1-2\n3-5\n6-10\n11+";

    $test_cases = [
      ['index' => 0, 'expected' => '0'],
      ['index' => 1, 'expected' => '1-2'],
      ['index' => 2, 'expected' => '3-5'],
      ['index' => 3, 'expected' => '6-10'],
      ['index' => 4, 'expected' => '11+'],
    ];

    foreach ($test_cases as $test_case) {
      $result_row = new ResultRow();
      $result_row->vv_total_page_views__range = (string) $test_case['index'];

      $this->field->field_alias = 'vv_total_page_views__range';

      $result = $this->field->render($result_row);

      $this->assertEquals($test_case['expected'], $result);
    }
  }

  /**
   * Tests the field plugin with empty ranges.
   *
   * @covers ::getRangeLabel
   */
  public function testFieldPluginWithEmptyRanges(): void {
    $this->field->options['ranges'] = '';

    $result_row = new ResultRow();
    $result_row->vv_total_page_views__range = '0';

    $this->field->field_alias = 'vv_total_page_views__range';

    $result = $this->field->render($result_row);

    $this->assertEquals('0', $result);
  }

  /**
   * Tests the field plugin with whitespace-only ranges.
   *
   * @covers ::getRangeLabel
   */
  public function testFieldPluginWithWhitespaceOnlyRanges(): void {
    $this->field->options['ranges'] = "  \n  \n  ";

    $result_row = new ResultRow();
    $result_row->vv_total_page_views__range = '0';

    $this->field->field_alias = 'vv_total_page_views__range';

    $result = $this->field->render($result_row);

    $this->assertEquals('0', $result);
  }

  /**
   * Tests the field plugin with non-existent index.
   *
   * @covers ::getRangeLabel
   */
  public function testFieldPluginWithNonExistentIndex(): void {
    $this->field->options['ranges'] = "0\n1\n2";

    $result_row = new ResultRow();
    $result_row->vv_total_page_views__range = '999';

    $this->field->field_alias = 'vv_total_page_views__range';

    $result = $this->field->render($result_row);

    $this->assertEquals('999', $result);
  }

}
