<?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 Chill\PersonBundle\Tests\Entity;

use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Household\Position;
use Chill\PersonBundle\Entity\Person;

/**
 * Unit tests for the person Entity.
 *
 * @internal
 *
 * @coversNothing
 */
final class PersonTest extends \PHPUnit\Framework\TestCase
{
    /**
     * Test if the getAccompanyingPeriodsOrdered function, for periods
     * starting at the same time order regarding to the closing date.
     */
    public function testAccompanyingPeriodOrderSameDateOpening()
    {
        $d = new \DateTime('2013/2/1');
        $p = new Person();
        $p->addAccompanyingPeriod(new AccompanyingPeriod($d));

        $g = new \DateTime('2013/4/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g);
        $p->close($period);

        $f = new \DateTime('2013/2/1');
        $p->open(new AccompanyingPeriod($f));

        $e = new \DateTime('2013/3/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e);
        $p->close($period);

        $r = $p->getAccompanyingPeriodsOrdered();

        $date = $r[0]->getClosingDate()->format('Y-m-d');

        $this->assertEquals($date, '2013-03-01');
    }

    /**
     * Test if the getAccompanyingPeriodsOrdered function return a list of
     * periods ordered ascendency.
     */
    public function testAccompanyingPeriodOrderWithUnorderedAccompanyingPeriod()
    {
        $d = new \DateTime('2013/2/1');
        $p = new Person();
        $p->addAccompanyingPeriod(new AccompanyingPeriod($d));

        $e = new \DateTime('2013/3/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e);
        $p->close($period);

        $f = new \DateTime('2013/1/1');
        $p->open(new AccompanyingPeriod($f));

        $g = new \DateTime('2013/4/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g);
        $p->close($period);

        $r = $p->getAccompanyingPeriodsOrdered();

        $date = $r[0]->getOpeningDate()->format('Y-m-d');

        $this->assertEquals($date, '2013-01-01');
    }

    /**
     * Test if the function checkAccompanyingPeriodIsNotCovering returns
     * the good constant when two periods are collapsing : a period
     * is covering another one : start_1 < start_2 & end_2 < end_1.
     */
    public function testDateCoveringWithCoveringAccompanyingPeriod()
    {
        $d = new \DateTime('2013/2/1');
        $p = new Person();
        $p->addAccompanyingPeriod(new AccompanyingPeriod($d));

        $e = new \DateTime('2013/3/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e);
        $p->close($period);

        $f = new \DateTime('2013/1/1');
        $p->open(new AccompanyingPeriod($f));

        $g = new \DateTime('2013/4/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g);
        $p->close($period);

        $r = $p->checkAccompanyingPeriodsAreNotCollapsing();

        $this->assertEquals($r['result'], Person::ERROR_PERIODS_ARE_COLLAPSING);
    }

    /**
     * Test the creation of an accompanying, its closure and the access to
     * the current accompaniying period via the getCurrentAccompanyingPeriod
     * function.
     */
    public function testGetCurrentAccompanyingPeriod()
    {
        $d = new \DateTime('yesterday');
        $p = new Person();
        $p->addAccompanyingPeriod(new AccompanyingPeriod($d));

        $period = $p->getCurrentAccompanyingPeriod();

        $this->assertInstanceOf(AccompanyingPeriod::class, $period);
        $this->assertTrue($period->isOpen());
        $this->assertEquals($d, $period->getOpeningDate());

        // close and test
        $period->setClosingDate(new \DateTime('tomorrow'));

        $shouldBeNull = $p->getCurrentAccompanyingPeriod();
        $this->assertNull($shouldBeNull);
    }

    public function testIsSharingHousehold()
    {
        $person = new Person();
        $household = new Household();
        $positionShare = (new Position())
            ->setShareHousehold(true);
        $positionNotShare = (new Position())
            ->setShareHousehold(false);

        $membership1 = (new HouseholdMember())
            ->setStartDate(new \DateTimeImmutable('10 years ago'))
            ->setEndDate(new \DateTimeImmutable('5 years ago'))
            ->setPerson($person)
            ->setPosition($positionShare);
        $household->addMember($membership1);

        $membership2 = (new HouseholdMember())
            ->setStartDate(new \DateTimeImmutable('4 years ago'))
            ->setEndDate(new \DateTimeImmutable('2 years ago'))
            ->setPerson($person)
            ->setPosition($positionNotShare);
        $household->addMember($membership2);

        $this->assertEquals(2, $person->getHouseholdParticipations()
            ->count());

        $this->assertFalse($person->isSharingHousehold());
        $this->assertTrue($person->isSharingHousehold(
            new \DateTimeImmutable('6 years ago')
        ));
        $this->assertFalse($person->isSharingHousehold(
            new \DateTimeImmutable('3 years ago')
        ));
    }

    /**
     * Test if the function checkAccompanyingPeriodIsNotCovering returns
     * the good constant when two periods are collapsing : a period is open
     * before an existing period.
     */
    public function testNotOpenAFileReOpenedLater()
    {
        $d = new \DateTime('2013/2/1');
        $p = new Person();
        $p->addAccompanyingPeriod(new AccompanyingPeriod($d));

        $e = new \DateTime('2013/3/1');
        $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e);
        $p->close($period);

        $f = new \DateTime('2013/1/1');
        $p->open(new AccompanyingPeriod($f));

        $r = $p->checkAccompanyingPeriodsAreNotCollapsing();

        $this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD);
    }

    public function testSetCenter()
    {
        $person = new Person();
        $centerA = new Center();
        $centerB = new Center();

        $this->assertCount(0, $person->getCenterHistory());
        $this->assertNull($person->getCenter());
        $this->assertNull($person->getCenterCurrent());

        $person->setCenter($centerA);

        $this->assertCount(1, $person->getCenterHistory());
        $this->assertSame($centerA, $person->getCenter());
        $this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
        $this->assertSame($centerA, $person->getCenterCurrent()->getCenter());

        $person->setCenter($centerB);

        $this->assertCount(2, $person->getCenterHistory());
        $this->assertSame($centerB, $person->getCenter());
        $this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
        $this->assertSame($centerB, $person->getCenterCurrent()->getCenter());
    }
}
