<?php
declare(strict_types=1);

namespace App\Service\Constraint;

use App\Entity\Access\Access;
use App\Service\Organization\Utils as OrganizationUtils;
use Doctrine\ORM\EntityManagerInterface;

/**
 * Classe ActivityYearConstraint qui définie l'année de début (et de fin dans le cas d'une période custom)
 * par rapport aux contraintes temporelles choisies par un utilisateur.
 */
class ActivityYearConstraint extends AbstractTimeConstraintUtils
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private OrganizationUtils $organizationUtils
    )
    { }

    /**
     * Main method
     *
     * @param int $accessID
     * @return array<string, array<string, list<int>>>
     * @throws \Exception
     */
    public function invoke(int $accessID): array
    {
        $access = $this->entityManager->getRepository(Access::class)->find($accessID);
        $historical = $access->getHistorical();

        $contraints = [
            self::START_KEY => [],
            self::END_KEY => []
        ];

        if($this->hasCustomPeriods($historical)){
            $periods = $this->getRangeYear($access, $historical['dateStart'], $historical['dateEnd']);
            $contraints = $this->addConstraint($contraints, $this->customConstraint($periods));
        }else{
            $year = $access->getActivityYear();
            if($historical['present']) $contraints = $this->addConstraint($contraints, $this->presentConstraint($year));
            if($historical['past']) $contraints = $this->addConstraint($contraints, $this->pastConstraint($year));
            if($historical['future']) $contraints = $this->addConstraint($contraints, $this->futureConstraint($year));
        }
        return $this->cleanConstraints($contraints);
    }

    /**
     * Retourne le tableau des années comprises dans la période custom
     * @param Access $access
     * @param string $dateStart
     * @param string $dateEnd
     * @return int[]
     */
    protected function getRangeYear(Access $access, string $dateStart, string $dateEnd): array
    {
        $organization = $access->getOrganization();
        return [
            OrganizationUtils::START_DATE_KEY => $this->organizationUtils->getActivityYearSwitchDate($organization, new \DateTime($dateStart)),
            OrganizationUtils::END_DATE_KEY => $this->organizationUtils->getActivityYearSwitchDate($organization, new \DateTime($dateEnd))
        ];
    }

    /**
     * Une période est dans le présent si :
     * - l'année de début est égale (=) à l'année à afficher
     * @param int $year
     * @return array<string, list<int>>
     */
    protected function presentConstraint(int $year): array
    {
        return [
          self::START_KEY => [
              $year => self::EQUAL
          ]
        ];
    }

    /**
     * Une période est dans le passée si :
     * - l'année de début est plus petite (<) à l'année à afficher
     * @param int $year
     * @return array<string, list<int>>
     */
    protected function pastConstraint(int $year): array
    {
        return [
            self::END_KEY => [
                $year => self::INF
            ]
        ];
    }

    /**
     * Une période est dans le futur si :
     * - l'année de début est plus grande (>) à l'année à afficher
     * @param int $year
     * @return array<string, list<int>>
     */
    protected function futureConstraint(int $year): array
    {
        return [
            self::START_KEY => [
                $year => self::SUP
            ]
        ];
    }

    /**
     * Une période est dans une contrainte custom si :
     *
     * - l'année de début est plus grande ou égale (>=) à l'année de départ
     * - l'année de début est plus petite ou égale (<=) à l'année de fin
     *
     * @param array<int> $years
     * @return array<string, list<int>>
     */
    protected function customConstraint(array $years): array
    {
        return [
            self::START_KEY => [
                $years[OrganizationUtils::START_DATE_KEY]  => self::SUP + self::EQUAL,
                $years[OrganizationUtils::END_DATE_KEY] => self::INF + self::EQUAL
            ]
        ];
    }
}
