<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Validator\AccompanyingPeriod;

use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlapValidator;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;

/**
 * @internal
 *
 * @coversNothing
 */
class ParticipationOverlapValidatorTest extends ConstraintValidatorTestCase
{
    use ProphecyTrait;

    public function testNoViolation(): void
    {
        $constraint = $this->getConstraint();

        $period = new AccompanyingPeriod();
        $person1 = new Person();
        $person2 = new Person();

        $period->createParticipationFor($person1);
        $period->createParticipationFor($person2);

        $this->validator->validate($period->getParticipations(), $constraint);

        $this->assertNoViolation();
    }

    public function testHasTwoParticipationsOverlaps(): void
    {
        $constraint = $this->getConstraint();

        $period = new AccompanyingPeriod();
        $person1 = new Person();
        $reflectionPerson = new \ReflectionClass($person1);
        $personId = $reflectionPerson->getProperty('id');
        $personId->setAccessible(true);
        $personId->setValue($person1, 1);
        $person2 = new Person();

        $period->createParticipationFor($person1);
        $period->createParticipationFor($person1);
        $period->createParticipationFor($person2);

        $this->validator->validate($period->getParticipations(), $constraint);

        $this->buildViolation('participation-overlaps')
            ->setParameters([
                '{{ start }}' => (new \DateTimeImmutable('today'))->format('d-m-Y'),
                '{{ end }}' => null,
                '{{ ids }}' => [null, null],
                '{{ name }}' => 'person',
            ])
            ->assertRaised();
    }

    public function testHasTwoParticipationsButDoNotOverlaps(): void
    {
        $constraint = $this->getConstraint();

        $period = new AccompanyingPeriod();
        $person1 = new Person();
        $reflectionPerson = new \ReflectionClass($person1);
        $personId = $reflectionPerson->getProperty('id');
        $personId->setAccessible(true);
        $personId->setValue($person1, 1);
        $person2 = new Person();

        $participation1 = $period->createParticipationFor($person1);
        $period->createParticipationFor($person1);
        $participation1->setEndDate(new \DateTime('now'));
        $period->createParticipationFor($person2);

        $this->validator->validate($period->getParticipations(), $constraint);

        $this->assertNoViolation();
    }

    protected function createValidator(): ParticipationOverlapValidator
    {
        $personRender = $this->prophesize(PersonRenderInterface::class);
        $personRender->renderString(Argument::type(Person::class), [])
            ->willReturn('person');
        $thirdPartyRender = $this->prophesize(ThirdPartyRender::class);
        $thirdPartyRender->renderString(Argument::type(ThirdParty::class), [])
            ->willReturn('third-party');

        return new ParticipationOverlapValidator(
            $personRender->reveal(),
            $thirdPartyRender->reveal()
        );
    }

    public function getConstraint(): ParticipationOverlap
    {
        return new ParticipationOverlap(['message' => 'participation-overlaps']);
    }
}
