<?php

namespace Drupal\Tests\eb\Unit\Result;

use Drupal\eb\Result\ValidationResult;
use Drupal\Tests\UnitTestCase;

/**
 * Unit tests for ValidationResult value object.
 *
 * @coversDefaultClass \Drupal\eb\Result\ValidationResult
 * @group eb
 */
class ValidationResultTest extends UnitTestCase {

  /**
   * Tests new result is valid by default.
   *
   * @covers ::isValid
   * @covers ::__construct
   */
  public function testNewResultIsValid(): void {
    $result = new ValidationResult();

    $this->assertTrue($result->isValid());
  }

  /**
   * Tests result with errors is not valid.
   *
   * @covers ::isValid
   */
  public function testResultWithErrorsIsNotValid(): void {
    $result = new ValidationResult([
      ['message' => 'Error message', 'field' => '', 'code' => ''],
    ]);

    $this->assertFalse($result->isValid());
  }

  /**
   * Tests adding an error.
   *
   * @covers ::addError
   * @covers ::getErrors
   */
  public function testAddError(): void {
    $result = new ValidationResult();

    $result->addError('Test error', 'field_name', 'error_code');

    $this->assertFalse($result->isValid());
    $errors = $result->getErrors();
    $this->assertCount(1, $errors);
    $this->assertEquals('Test error', $errors[0]['message']);
    $this->assertEquals('field_name', $errors[0]['field']);
    $this->assertEquals('error_code', $errors[0]['code']);
    $this->assertEquals('error', $errors[0]['severity']);
  }

  /**
   * Tests adding multiple errors.
   *
   * @covers ::addError
   */
  public function testAddMultipleErrors(): void {
    $result = new ValidationResult();

    $result->addError('Error 1', 'field_1', 'code_1');
    $result->addError('Error 2', 'field_2', 'code_2');
    $result->addError('Error 3', 'field_3', 'code_3');

    $errors = $result->getErrors();
    $this->assertCount(3, $errors);
  }

  /**
   * Tests adding a warning.
   *
   * @covers ::addWarning
   * @covers ::getWarnings
   */
  public function testAddWarning(): void {
    $result = new ValidationResult();

    $result->addWarning('Test warning', 'field_name', 'warning_code');

    // Warnings don't make result invalid.
    $this->assertTrue($result->isValid());
    $warnings = $result->getWarnings();
    $this->assertCount(1, $warnings);
    $this->assertEquals('Test warning', $warnings[0]['message']);
    $this->assertEquals('field_name', $warnings[0]['field']);
    $this->assertEquals('warning_code', $warnings[0]['code']);
    $this->assertEquals('warning', $warnings[0]['severity']);
  }

  /**
   * Tests adding multiple warnings.
   *
   * @covers ::addWarning
   */
  public function testAddMultipleWarnings(): void {
    $result = new ValidationResult();

    $result->addWarning('Warning 1');
    $result->addWarning('Warning 2');

    $this->assertCount(2, $result->getWarnings());
  }

  /**
   * Tests adding an informational message.
   *
   * @covers ::addMessage
   * @covers ::getMessages
   */
  public function testAddMessage(): void {
    $result = new ValidationResult();

    $result->addMessage('Info message');

    // Messages don't affect validity.
    $this->assertTrue($result->isValid());
    $messages = $result->getMessages();
    $this->assertCount(1, $messages);
    $this->assertEquals('Info message', $messages[0]);
  }

  /**
   * Tests constructor with initial values.
   *
   * @covers ::__construct
   */
  public function testConstructorWithInitialValues(): void {
    $errors = [
      ['message' => 'Error 1', 'field' => '', 'code' => '', 'severity' => 'error'],
    ];
    $warnings = [
      ['message' => 'Warning 1', 'field' => '', 'code' => '', 'severity' => 'warning'],
    ];
    $messages = ['Info 1', 'Info 2'];

    $result = new ValidationResult($errors, $warnings, $messages);

    $this->assertFalse($result->isValid());
    $this->assertCount(1, $result->getErrors());
    $this->assertCount(1, $result->getWarnings());
    $this->assertCount(2, $result->getMessages());
  }

  /**
   * Tests error with default parameters.
   *
   * @covers ::addError
   */
  public function testErrorWithDefaultParameters(): void {
    $result = new ValidationResult();

    $result->addError('Just a message');

    $errors = $result->getErrors();
    $this->assertEquals('', $errors[0]['field']);
    $this->assertEquals('', $errors[0]['code']);
    $this->assertEquals('error', $errors[0]['severity']);
  }

  /**
   * Tests error with custom severity.
   *
   * @covers ::addError
   */
  public function testErrorWithCustomSeverity(): void {
    $result = new ValidationResult();

    $result->addError('Critical error', '', '', 'critical');

    $errors = $result->getErrors();
    $this->assertEquals('critical', $errors[0]['severity']);
  }

  /**
   * Tests warning with default parameters.
   *
   * @covers ::addWarning
   */
  public function testWarningWithDefaultParameters(): void {
    $result = new ValidationResult();

    $result->addWarning('Just a warning');

    $warnings = $result->getWarnings();
    $this->assertEquals('', $warnings[0]['field']);
    $this->assertEquals('', $warnings[0]['code']);
  }

  /**
   * Tests empty result arrays.
   *
   * @covers ::getErrors
   * @covers ::getWarnings
   * @covers ::getMessages
   */
  public function testEmptyResultArrays(): void {
    $result = new ValidationResult();

    $this->assertIsArray($result->getErrors());
    $this->assertEmpty($result->getErrors());
    $this->assertIsArray($result->getWarnings());
    $this->assertEmpty($result->getWarnings());
    $this->assertIsArray($result->getMessages());
    $this->assertEmpty($result->getMessages());
  }

}
