<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Unit\Plugin\VisitorsEvent;

use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\visitors\Plugin\VisitorsEvent\Form;

/**
 * @coversDefaultClass \Drupal\visitors\Plugin\VisitorsEvent\Form
 * @group visitors
 */
class FormTest extends UnitTestCase {

  /**
   * The route match service.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $routeMatch;

  /**
   * The form plugin.
   *
   * @var \Drupal\visitors\Plugin\VisitorsEvent\Form
   */
  protected $plugin;

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

    $this->routeMatch = $this->createMock(RouteMatchInterface::class);

    $this->plugin = new Form(
      [],
      'form',
      [],
      $this->routeMatch
    );
  }

  /**
   * @covers ::process
   */
  public function testProcessWithNoForms(): void {
    $context = [
      'route' => 'test.form',
      'path' => '/test-form',
    ];

    $result = $this->plugin->process($context);
    $this->assertNull($result);
  }

  /**
   * @covers ::process
   */
  public function testProcessWithSingleForm(): void {
    $form_id = 'test_form';
    $base_form_id = 'test_base_form';

    // Set up the drupal_static variable.
    $forms = &drupal_static('visitors_form_alter');
    $forms = [];
    $forms[$form_id] = $base_form_id;

    $context = [
      'route' => 'test.form',
      'path' => '/test-form',
    ];

    $result = $this->plugin->process($context);

    $this->assertIsArray($result);
    $this->assertEquals('view', $result['event']);
    $this->assertEquals($base_form_id, $result['variables']['plugin_var_3']);
    $this->assertEquals($form_id, $result['variables']['plugin_var_4']);

    // Clean up static variable.
    drupal_static_reset('visitors_form_alter');
  }

  /**
   * @covers ::process
   */
  public function testProcessWithValidation(): void {
    $form_id = 'test_form';
    $base_form_id = 'test_base_form';

    // Set up the drupal_static variables.
    $forms = &drupal_static('visitors_form_alter', []);
    $forms[$form_id] = $base_form_id;

    $form_validate = &drupal_static('visitors_form_validate', []);
    $form_validate[$form_id] = $base_form_id;

    $context = [
      'route' => 'test.form',
      'path' => '/test-form',
    ];

    $result = $this->plugin->process($context);

    $this->assertIsArray($result);
    $this->assertEquals('validate', $result['event']);
    $this->assertEquals($base_form_id, $result['variables']['plugin_var_3']);
    $this->assertEquals($form_id, $result['variables']['plugin_var_4']);

    // Clean up static variables.
    drupal_static_reset('visitors_form_alter');
    drupal_static_reset('visitors_form_validate');
  }

  /**
   * @covers ::process
   */
  public function testProcessWithSubmission(): void {
    $form_id = 'test_form';
    $base_form_id = 'test_base_form';

    // Set up the drupal_static variables.
    $forms = &drupal_static('visitors_form_alter', []);
    $forms[$form_id] = $base_form_id;

    $form_submit = &drupal_static('visitors_form_submit', []);
    $form_submit[$form_id] = $base_form_id;

    $context = [
      'route' => 'test.form',
      'path' => '/test-form',
    ];

    $result = $this->plugin->process($context);

    $this->assertIsArray($result);
    $this->assertEquals('submit', $result['event']);
    $this->assertEquals($base_form_id, $result['variables']['plugin_var_3']);
    $this->assertEquals($form_id, $result['variables']['plugin_var_4']);

    // Clean up static variables.
    drupal_static_reset('visitors_form_alter');
    drupal_static_reset('visitors_form_submit');
  }

  /**
   * @covers ::validate
   */
  public function testValidate(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_object = $this->createMock('\Drupal\Core\Entity\EntityForm');

    $form_id = 'test_form';
    $base_form_id = 'test_base_form';

    $form_object->expects($this->once())
      ->method('getFormId')
      ->willReturn($form_id);
    $form_object->expects($this->once())
      ->method('getBaseFormId')
      ->willReturn($base_form_id);
    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn($form_object);

    Form::validate($form, $form_state);

    $form_validate = &drupal_static('visitors_form_validate');
    $this->assertEquals($base_form_id, $form_validate[$form_id]);

    // Clean up static variable.
    drupal_static_reset('visitors_form_validate');
  }

  /**
   * @covers ::submit
   */
  public function testSubmit(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_object = $this->createMock('\Drupal\Core\Entity\EntityForm');

    $form_id = 'test_form';
    $base_form_id = 'test_base_form';

    $form_object->expects($this->once())
      ->method('getFormId')
      ->willReturn($form_id);
    $form_object->expects($this->once())
      ->method('getBaseFormId')
      ->willReturn($base_form_id);
    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn($form_object);

    Form::submit($form, $form_state);

    $form_submit = &drupal_static('visitors_form_submit');
    $this->assertEquals($base_form_id, $form_submit[$form_id]);

    // Clean up static variable.
    drupal_static_reset('visitors_form_submit');
  }

  /**
   * @covers ::validate
   */
  public function testValidateWithNoFormObject(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn(NULL);

    Form::validate($form, $form_state);

    $form_validate = &drupal_static('visitors_form_validate');
    $this->assertEmpty($form_validate);

    // Clean up static variable.
    drupal_static_reset('visitors_form_validate');
  }

  /**
   * @covers ::submit
   */
  public function testSubmitWithNoFormObject(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn(NULL);

    Form::submit($form, $form_state);

    $form_submit = &drupal_static('visitors_form_submit');
    $this->assertEmpty($form_submit);

    // Clean up static variable.
    drupal_static_reset('visitors_form_submit');
  }

  /**
   * @covers ::validate
   */
  public function testValidateWithNoBaseFormId(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_object = $this->createMock(FormInterface::class);

    $form_id = 'test_form';
    $form_validate = &drupal_static('visitors_form_validate');
    $form_validate = [];
    $form_object->expects($this->once())
      ->method('getFormId')
      ->willReturn($form_id);

    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn($form_object);

    Form::validate($form, $form_state);

    $form_validate = &drupal_static('visitors_form_validate');

    $this->assertEquals($form_id, $form_validate[$form_id]);

    // Clean up static variable.
    drupal_static_reset('visitors_form_validate');
  }

  /**
   * @covers ::submit
   */
  public function testSubmitWithNoBaseFormId(): void {
    $form = [];
    $form_state = $this->createMock(FormState::class);
    $form_object = $this->createMock(FormInterface::class);

    $form_id = 'test_form';

    $form_object->expects($this->once())
      ->method('getFormId')
      ->willReturn($form_id);

    $form_state->expects($this->once())
      ->method('getFormObject')
      ->willReturn($form_object);

    Form::submit($form, $form_state);

    $form_submit = &drupal_static('visitors_form_submit');
    $this->assertEquals($form_id, $form_submit[$form_id]);

    // Clean up static variable.
    drupal_static_reset('visitors_form_submit');
  }

}
