<?php

declare(strict_types=1);

namespace App\Service\OnlineRegistration;

use App\Entity\Access\Access;
use App\Entity\AccessWish\AccessWish;
use App\Enum\OnlineRegistration\RegistrationStatusEnum;
use App\Enum\OnlineRegistration\WishRegistrationEnum;
use App\Service\Utils\DatesUtils;

/**
 * --- SERVICE INUTILISE POUR LE MOMENT ---
 * Fournit le statut de l'enregistrement en ligne d'un Access.
 */
class RegistrationStatusService
{
    /**
     * Temps de validité du statut (en jours)
     * (correspond au temps d'affichage de l'avertissement dans l'application).
     */
    public const DISPLAYING_TIME = 30;

    public function __construct(
        private OnlineRegistrationService $onlineRegistrationService,
    ) {
    }

    /**
     * Détermine er retourne le statut de l'enregistrement en ligne d'un Access.
     */
    public function getStatus(Access $access): ?RegistrationStatusEnum
    {
        $currentAccessWish = $this->onlineRegistrationService->getCurrentAccessWish($access);
        if ($currentAccessWish === null) {
            // TODO: est-ce qu'il ne faudrait pas plutôt lever une erreur ici plutôt que de retourner null?
            return null;
        }

        if (!$currentAccessWish->getAccessFamilyWish()->isRegistrationCompleted()) {
            // TODO: est-ce qu'on ne retournerait pas un statut incomplet plutôt que null?
            return null;
        }

        $wishesCountByStatus = $this->countEducationsByRegistrationStatus($currentAccessWish);
        if ($wishesCountByStatus === null) {
            // TODO: est-ce qu'il ne faudrait pas plutôt lever une erreur ici plutôt que de retourner null?
            return null;
        }

        $hasNegotiable = $wishesCountByStatus[RegistrationStatusEnum::NEGOTIABLE->value] > 0;
        $hasAccepted = $wishesCountByStatus[RegistrationStatusEnum::ACCEPTED->value] > 0;
        $hasPending = $wishesCountByStatus[RegistrationStatusEnum::PENDING->value] > 0;
        $hasDenied = $wishesCountByStatus[RegistrationStatusEnum::DENIED->value] > 0;

        // Après acceptation ou refus, le bandeau est affiché pour une durée de 30 jours.
        if (
            !$hasNegotiable && ($hasAccepted || $hasDenied)
            && $this->getDaysSinceLastUpdate($currentAccessWish) > self::DISPLAYING_TIME
        ) {
            // TODO: est-ce qu'on ne retournerait pas ici un statut EXPIRED par ex?
            return null;
        }

        if (!$hasAccepted && !$hasPending && $hasNegotiable) {
            // La demande est dans la liste des inscriptions en ligne et n'a pas été traitée par l'administration
            return RegistrationStatusEnum::NEGOTIABLE;
        } elseif ($hasPending && !$hasAccepted) {
            // La demande est dans la liste des inscriptions en ligne car l'administration a mis "En attente" à au moins l'un des enseignements.
            return RegistrationStatusEnum::PENDING;
        } elseif ($hasAccepted) {
            // La demande a été traitée par l'administration. L'élève a été accepté pour au moins l'une de ses activités.
            // Et il a été placé dans la liste des "Inscriptions rentrée prochaine".
            return RegistrationStatusEnum::ACCEPTED;
        } elseif ($hasDenied && !$hasNegotiable) {
            // La demande a été traitée par l'administration. L'élève n'a pas été accepté dans l'établissement.
            // Il est dans la liste des "Inscriptions en ligne" avec le statut "Refusé" sur tous ses enseignements.
            return RegistrationStatusEnum::DENIED;
        }

        // TODO: est-ce qu'il ne faudrait pas plutôt lever une erreur ici plutôt que de retourner null?
        return null;
    }

    public function getDaysSinceLastUpdate(AccessWish $accessWish): int
    {
        $lastUpdate = $accessWish->getAccessFamilyWish()->getUpdateDate();

        return DatesUtils::daysSince($lastUpdate);
    }

    /**
     * Retourne le décompte des souhaits de l'utilisateur par RegistrationStatus, ou null si aucun souhaits.
     *
     * @return array<string, int>|null
     */
    protected function countEducationsByRegistrationStatus(AccessWish $currentAccessWish): ?array
    {
        $wishes = $currentAccessWish->getEducationStudentWishes();
        $reregistrationWishes = $currentAccessWish->getEducationStudentReregistrationsWishes();

        if ($reregistrationWishes->isEmpty() && $wishes->isEmpty()) {
            // TODO: est-ce qu'il ne faudrait pas plutôt lever une erreur ici plutôt que de retourner null?
            return null;
        }

        $registrationStatuses = [
            RegistrationStatusEnum::NEGOTIABLE->value => 0,
            RegistrationStatusEnum::ACCEPTED->value => 0,
            RegistrationStatusEnum::PENDING->value => 0,
            RegistrationStatusEnum::DENIED->value => 0,
        ];

        foreach ($reregistrationWishes as $reregistrationWish) {
            if ($reregistrationWish->getWishRegistration() !== WishRegistrationEnum::REREGISTER) {
                continue;
            }
            ++$registrationStatuses[$reregistrationWish->getRegistrationStatus()];
        }

        foreach ($wishes as $educationStudentWish) {
            ++$registrationStatuses[$educationStudentWish->getRegistrationStatus()];
        }

        return $registrationStatuses;
    }
}
