<?php

namespace Tests\Unit\Framework\Validator;

use Openguru\OpenCartFramework\Validator\ValidationRuleNotFoundException;
use Openguru\OpenCartFramework\Validator\ValidationRules\Required;
use Openguru\OpenCartFramework\Validator\Validator;
use Tests\TestCase;

/**
 * @coversDefaultClass \Openguru\OpenCartFramework\Validator\Validator
 */
class ValidatorTest extends TestCase
{
    /**
     * @covers \Openguru\OpenCartFramework\Validator\Validator::fails
     * @covers \Openguru\OpenCartFramework\Validator\Validator::make
     */
    public function testValidateBasic(): void
    {
        $validator = new Validator();
        $this->assertFalse($validator->make([], [])->fails());
    }

    /**
     * @covers \Openguru\OpenCartFramework\Validator\Validator::fails
     */
    public function testThrowExceptionIfRuleNotFound(): void
    {
        $validator = new Validator();
        $v = $validator->make([], [
            'field' => 'not_exists_rule',
        ]);

        $this->expectException(ValidationRuleNotFoundException::class);

        $v->fails();
    }

    public function testRequiredForNonExistentField(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['xyz' => 'abc'], ['foo' => 'required']);

        $this->assertTrue($v->fails());
        $this->assertEquals(1, $v->getErrors()->count());
        $this->assertEquals(['foo is required'], $v->getErrors()->first());
    }

    public function testRequiredForEmptyField(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => ''], ['foo' => 'required']);

        $this->assertTrue($v->fails());
        $this->assertEquals(1, $v->getErrors()->count());
        $this->assertEquals(['foo is required'], $v->getErrors()->first());
    }

    public function testRequiredForFalseValue(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => false], ['foo' => 'required']);

        $this->assertFalse($v->fails());
    }

    public function testRequiredForNullValue(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => null], ['foo' => 'required']);

        $this->assertTrue($v->fails());
        $this->assertEquals(1, $v->getErrors()->count());
        $this->assertEquals(['foo is required'], $v->getErrors()->first());
    }

    public function testRequiredForZero(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => 0], ['foo' => 'required']);

        $this->assertFalse($v->fails());
    }

    public function testRequiredForZeroString(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => "0"], ['foo' => 'required']);

        $this->assertFalse($v->fails());
    }

    public function testCustomValidationMessages(): void
    {
        $customMessages = [
            'required' => ':field is very required',
        ];

        $validator = new Validator([
            'required' => fn () => new Required(),
        ], $customMessages);

        $v = $validator->make(['foo' => ''], ['foo' => 'required']);

        $this->assertTrue($v->fails());
        $this->assertEquals(1, $v->getErrors()->count());
        $this->assertEquals(['foo is very required'], $v->getErrors()->first());
    }

    public function testCustomFieldNames(): void
    {
        $validator = new Validator([
            'required' => fn () => new Required(),
        ]);

        $v = $validator->make(['foo' => ''], [
            'foo' => 'required'
        ], [
            'foo' => 'My Field'
        ]);

        $this->assertTrue($v->fails());
        $this->assertEquals(1, $v->getErrors()->count());
        $this->assertEquals(['My Field is required'], $v->getErrors()->first());
    }
}
