<?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\Event\Person;

use Chill\MainBundle\Entity\Address;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
use Symfony\Contracts\EventDispatcher\Event;

class PersonAddressMoveEvent extends Event
{
    final public const PERSON_MOVE_POST = 'chill_person.person_move_post';

    private ?Address $nextAddress = null;

    private ?HouseholdMember $nextMembership = null;

    private ?Address $previousAddress = null;

    private ?HouseholdMember $previousMembership = null;

    public function __construct(private readonly Person $person) {}

    /**
     * Get the date of the move.
     *
     * It might be either:
     *
     * * the date of the new membership;
     * * or the date of the move
     * * or the date when the household leaving take place (the end date of the previous membership)
     */
    public function getMoveDate(): \DateTimeImmutable
    {
        if ($this->personLeaveWithoutHousehold()) {
            return $this->getPreviousMembership()->getEndDate();
        }

        if ($this->personChangeHousehold()) {
            return $this->getNextMembership()->getStartDate();
        }

        // person is changing address without household
        return \DateTimeImmutable::createFromMutable($this->getNextAddress()->getValidFrom());
    }

    public function getNextAddress(): ?Address
    {
        if (null !== $this->getNextMembership()) {
            return $this->getNextMembership()->getHousehold()
                ->getCurrentAddress(
                    \DateTime::createFromImmutable($this->getMoveDate())
                );
        }

        return $this->nextAddress;
    }

    public function getNextHousehold(): ?Household
    {
        if (null !== $nextMembership = $this->getNextMembership()) {
            return $nextMembership->getHousehold();
        }

        return null;
    }

    public function getNextMembership(): ?HouseholdMember
    {
        return $this->nextMembership;
    }

    public function getPerson(): Person
    {
        return $this->person;
    }

    public function getPreviousAddress(): ?Address
    {
        if (null !== $this->getPreviousMembership()) {
            return $this->getPreviousMembership()->getHousehold()
                ->getCurrentAddress(
                    \DateTime::createFromImmutable($this->getMoveDate())
                );
        }

        return $this->previousAddress;
    }

    public function getPreviousHousehold(): ?Household
    {
        if (null !== $previousMembership = $this->getPreviousMembership()) {
            return $previousMembership->getHousehold();
        }

        return null;
    }

    public function getPreviousMembership(): ?HouseholdMember
    {
        return $this->previousMembership;
    }

    public function personChangeAddress(): bool
    {
        return $this->getPreviousAddress() !== $this->getNextAddress();
    }

    /**
     * Return true if the user change household (this include the fact that a person
     * leave household without a new one).
     */
    public function personChangeHousehold(): bool
    {
        return $this->getPreviousHousehold() !== $this->getNextHousehold();
    }

    public function personLeaveWithoutHousehold(): bool
    {
        return null === $this->getNextMembership()
            && null === $this->getNextAddress();
    }

    public function setNextAddress(?Address $nextAddress): PersonAddressMoveEvent
    {
        $this->nextAddress = $nextAddress;

        return $this;
    }

    public function setNextMembership(?HouseholdMember $nextMembership): PersonAddressMoveEvent
    {
        $this->nextMembership = $nextMembership;

        return $this;
    }

    public function setPreviousAddress(?Address $previousAddress): PersonAddressMoveEvent
    {
        $this->previousAddress = $previousAddress;

        return $this;
    }

    public function setPreviousMembership(?HouseholdMember $previousMembership): PersonAddressMoveEvent
    {
        $this->previousMembership = $previousMembership;

        return $this;
    }

    /**
     * Will the change affect this date ?
     */
    public function willChangeBeActiveAt(\DateTimeImmutable $date): bool
    {
        if ($this->getMoveDate() < $date && $this->personLeaveWithoutHousehold()) {
            return true;
        }

        if ($this->personChangeHousehold()) {
            if ($this->getMoveDate() > $date) {
                return false;
            }

            if (null === $this->getNextMembership()->getEndDate()) {
                return true;
            }

            if ($this->getNextMembership()->getEndDate() > $date) {
                return true;
            }
        } else {
            if ($this->getNextAddress()->getValidFrom() > $date) {
                return false;
            }

            if (null === $this->getNextAddress()->getValidTo()) {
                return true;
            }

            if ($this->getNextAddress()->getValidTo() > $date) {
                return true;
            }
        }

        return false;
    }
}
