<?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 Entity\Household;

use Chill\MainBundle\Entity\Address;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdComposition;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
use PHPUnit\Framework\TestCase;

/**
 * @internal
 *
 * @coversNothing
 */
final class HouseholdTest extends TestCase
{
    public function testGetMembersOnRange()
    {
        $household = new Household();

        $household->addMember($householdMemberA = (new HouseholdMember())
            ->setStartDate(new \DateTimeImmutable('2020-01-01'))
            ->setEndDate(new \DateTimeImmutable('2020-12-31'))
            ->setPerson(new Person()));
        $household->addMember($householdMemberB = (new HouseholdMember())
            ->setStartDate(new \DateTimeImmutable('2020-06-01'))
            ->setEndDate(new \DateTimeImmutable('2021-06-31'))
            ->setPerson(new Person()));
        $household->addMember($householdMemberC = (new HouseholdMember())
            ->setStartDate(new \DateTimeImmutable('2021-01-01'))
            ->setEndDate(null)
            ->setPerson(new Person()));

        $members = $household->getMembersOnRange(new \DateTimeImmutable('2019-01-01'), null);

        $this->assertCount(3, $members);
        $this->assertContains($householdMemberA, $members);
        $this->assertContains($householdMemberB, $members);
        $this->assertContains($householdMemberC, $members);

        $members = $household->getMembersOnRange(new \DateTimeImmutable('2020-01-01'), new \DateTimeImmutable('2020-07-01'));
        $this->assertCount(2, $members);
        $this->assertContains($householdMemberA, $members);
        $this->assertContains($householdMemberB, $members);
        $this->assertNotContains($householdMemberC, $members);

        $members = $household->getMembersOnRange(new \DateTimeImmutable('2020-01-01'), new \DateTimeImmutable('2022-12-31'));
        $this->assertCount(3, $members);
        $this->assertContains($householdMemberA, $members);
        $this->assertContains($householdMemberB, $members);
        $this->assertContains($householdMemberC, $members);

        $members = $household->getMembersOnRange(new \DateTimeImmutable('2021-01-01'), new \DateTimeImmutable('2022-12-31'));
        $this->assertCount(2, $members);
        $this->assertNotContains($householdMemberA, $members);
        $this->assertContains($householdMemberB, $members);
        $this->assertContains($householdMemberC, $members);
    }

    public function testHouseholdAddressConsistent()
    {
        $household = new Household();

        $lastAddress = new Address();
        $lastAddress->setValidFrom($yesterday = new \DateTime('yesterday'));
        $lastAddress->setValidTo(new \DateTime('tomorrow'));
        $household->addAddress($lastAddress);

        $this->assertNull($lastAddress->getValidTo());
        $this->assertEquals($yesterday, $lastAddress->getValidFrom());

        $previousAddress = new Address();
        $previousAddress->setValidFrom($oneMonthAgo = new \DateTime('1 month ago'));
        $previousAddress->setValidTo(new \DateTime('now'));
        $household->addAddress($previousAddress);

        $addresses = $household->getAddressesOrdered();
        $this->assertSame($previousAddress, $addresses[0]);
        $this->assertSame($lastAddress, $addresses[1]);

        $this->assertEquals($oneMonthAgo, $previousAddress->getValidFrom());
        $this->assertEquals($yesterday, $previousAddress->getValidTo());
        $this->assertEquals($yesterday, $lastAddress->getValidFrom());
        $this->assertNull($lastAddress->getValidTo());

        $futureAddress = new Address();
        $futureAddress->setValidFrom($tomorrow = new \DateTime('tomorrow'));
        $futureAddress->setValidTo(new \DateTime('2150-01-01'));
        $household->addAddress($futureAddress);

        $addresses = $household->getAddressesOrdered();
        $this->assertSame($previousAddress, $addresses[0]);
        $this->assertSame($lastAddress, $addresses[1]);
        $this->assertSame($futureAddress, $addresses[2]);

        $this->assertEquals($oneMonthAgo, $previousAddress->getValidFrom());
        $this->assertEquals($yesterday, $previousAddress->getValidTo());
        $this->assertEquals($yesterday, $lastAddress->getValidFrom());
        $this->assertEquals($tomorrow, $lastAddress->getValidTo());
        $this->assertEquals($tomorrow, $futureAddress->getValidFrom());
        $this->assertNull($futureAddress->getValidTo());
    }

    public function testHouseholdComposition()
    {
        $household = new Household();

        $household->addComposition(($first = new HouseholdComposition())
            ->setStartDate(new \DateTimeImmutable('2021-12-01')));

        $this->assertNull($first->getEndDate());

        $household->addComposition(($second = new HouseholdComposition())
            ->setStartDate(new \DateTimeImmutable('2021-12-31')));

        $this->assertEquals(new \DateTimeImmutable('2021-12-31'), $first->getEndDate());
        $this->assertEquals(new \DateTimeImmutable('2021-12-31'), $second->getStartDate());

        $household->addComposition(($inside = new HouseholdComposition())
            ->setStartDate(new \DateTimeImmutable('2021-12-15')));

        $this->assertEquals(new \DateTimeImmutable('2021-12-15'), $first->getEndDate());
        $this->assertEquals(new \DateTimeImmutable('2021-12-31'), $second->getStartDate());
        $this->assertEquals(new \DateTimeImmutable('2021-12-31'), $inside->getEndDate());
    }

    public function testHouseholdGetPersonsDuringMembership()
    {
        $household = new Household();
        $person1 = new Person();
        $person2 = new Person();
        $personOut = new Person();

        $household->addMember(
            $member1 = (new HouseholdMember())
                ->setStartDate(new \DateTimeImmutable('2021-01-01'))
                ->setEndDate(new \DateTimeImmutable('2021-12-01'))
                ->setPerson($person1)
        );

        $household->addMember(
            $member2a = (new HouseholdMember())
                ->setStartDate(new \DateTimeImmutable('2021-01-01'))
                ->setEndDate(new \DateTimeImmutable('2021-05-01'))
                ->setPerson($person2)
        );

        $household->addMember(
            $member2b = (new HouseholdMember())
                ->setStartDate(new \DateTimeImmutable('2021-11-01'))
                ->setEndDate(new \DateTimeImmutable('2022-06-01'))
                ->setPerson($person2)
        );

        $household->addMember(
            $memberOut = (new HouseholdMember())
                ->setStartDate(new \DateTimeImmutable('2019-01-01'))
                ->setEndDate(new \DateTimeImmutable('2019-12-01'))
                ->setPerson($personOut)
        );

        $this->assertCount(0, $household->getPersonsDuringMembership($memberOut));

        $this->assertCount(1, $household->getPersonsDuringMembership($member1));
        $this->assertContains($person2, $household->getPersonsDuringMembership($member1));

        $this->assertCount(1, $household->getPersonsDuringMembership($member2a));
        $this->assertContains($person1, $household->getPersonsDuringMembership($member2a));

        $this->assertCount(1, $household->getPersonsDuringMembership($member2b));
        $this->assertContains($person1, $household->getPersonsDuringMembership($member2b));
    }
}
