<?php

declare(strict_types=1);

namespace App\Service\OnChange\Organization;

use App\Entity\Booking\Course;
use App\Entity\Education\EducationNotationConfig;
use App\Entity\Organization\Parameters;
use App\Enum\Education\AdvancedEducationNotationTypeEnum;
use App\Message\Command\Parameters\AverageChange;
use App\Message\Command\Typo3\Typo3DeleteCommand;
use App\Message\Command\Typo3\Typo3UndeleteCommand;
use App\Message\Command\Typo3\Typo3UpdateCommand;
use App\Repository\Booking\CourseRepository;
use App\Service\Network\Utils as NetworkUtils;
use App\Service\OnChange\OnChangeContext;
use App\Service\OnChange\OnChangeDefault;
use App\Test\Service\OnChange\Organization\OnParametersChangeTest;
use App\Service\Organization\Utils as OrganizationUtils;
use Symfony\Component\Messenger\MessageBusInterface;

/**
 * Classe OnParametersChange qui comporte toutes les opérations automatiquent se produisant lors de l'évolution des paramètres
 */
class OnParametersChange extends OnChangeDefault
{
    public function __construct(
        private CourseRepository $courseRepository,
        private NetworkUtils $networkUtils,
        private OrganizationUtils $organizationUtils,
        private MessageBusInterface $messageBus
    ){ }

    /** @noinspection PhpParameterNameChangedDuringInheritanceInspection */
    public function validate(mixed $parameters, OnChangeContext $context): void
    {
        // Une structure CMF n'a pas le droit de désactiver son site typo3
        if (
            $parameters->getDesactivateOpentalentSiteWeb() === true &&
            $this->networkUtils->isCMFAndActiveNow($parameters->getOrganization())
        ) {
            throw new \RuntimeException('This structure is currently active in the CMF network, the website can not be disabled.');
        }
    }

    /**
     * @param Parameters $parameters
     * @throws \Exception
     * @noinspection PhpParameterNameChangedDuringInheritanceInspection
     */
    public function beforeChange($parameters, OnChangeContext $context): void
    {
        // Le type de notation a changé
        if(
            $context->previousData() &&
            $context->previousData()->getAdvancedEducationNotationType() !== $parameters->getAdvancedEducationNotationType()
        ){
            $this->onAdvancedEducationNotationTypeChange($parameters);
        }

        // La date de début d'activité change
        if(
            $context->previousData() &&
            $context->previousData()->getMusicalDate() !== $parameters->getMusicalDate()
        ){
            $this->onMusicalDateChange(
                $parameters,
                $context->previousData()->getMusicalDate()
            );
        }
    }

    /**
     * @param Parameters $parameters
     * @noinspection PhpParameterNameChangedDuringInheritanceInspection
     */
    public function onChange($parameters, OnChangeContext $context): void
    {
        // La note maximale du suivi pédagogique change
        if(
            $context->previousData() &&
            $context->previousData()->getAverage() !== $parameters->getAverage()
        ){
            $this->messageBus->dispatch(
                new AverageChange($parameters->getId())
            );
        }

        // Le customDomain a été modifié, on met à jour le site typo3 (s'il est actif)
        if(
            $context->previousData() &&
            !$parameters->getDesactivateOpentalentSiteWeb() &&
            $context->previousData()->getCustomDomain() !== $parameters->getCustomDomain()
        ){
            $this->messageBus->dispatch(
                new Typo3UpdateCommand($parameters->getOrganization()->getId())
            );
        }

        // Le site web opentalent a été désactivé / réactivé
        if(
            $context->previousData() &&
            $context->previousData()->getDesactivateOpentalentSiteWeb() !== $parameters->getDesactivateOpentalentSiteWeb()
        ){
            if ($parameters->getDesactivateOpentalentSiteWeb()) {
                $this->messageBus->dispatch(
                    new Typo3DeleteCommand($parameters->getOrganization()->getId())
                );
            } else {
                $this->messageBus->dispatch(
                    new Typo3UndeleteCommand($parameters->getOrganization()->getId())
                );
                $this->messageBus->dispatch(
                    new Typo3UpdateCommand($parameters->getOrganization()->getId())
                );
            }
        }
    }

    /**
     * Si le type de grilles d'évaluation évolue, il faut "nettoyer" les curriculums/teachers associés au type précédent
     *
     * @param Parameters $parameters
     * @see OnParametersChangeTest::testOnAdvancedEducationNotationTypeByTeachersChange()
     * @see OnParametersChangeTest::testOnAdvancedEducationNotationTypeByEducationChange()
     */
    public function onAdvancedEducationNotationTypeChange(Parameters $parameters): void {
        foreach ($parameters->getOrganization()->getEducationNotationConfigs() as $educationNotationConfig) {
            /** @var EducationNotationConfig $educationNotationConfig */
            if ($parameters->getAdvancedEducationNotationType() === AdvancedEducationNotationTypeEnum::BY_TEACHER()->getValue()) {
                foreach ($educationNotationConfig->getEducationCurriculums() as $educationCurriculum) {
                    $educationCurriculum->setEducationNotationConfig(null);
                }
            } else {
                foreach ($educationNotationConfig->getTeachers() as $teacher) {
                    $teacher->setEducationNotationConfig(null);
                }
            }
        }
    }

    /**
     * Permet de mettre à jour l'année de début des cours concernés suivant la date
     * de l'activité musicale qui vient d'être changée
     *
     * @param Parameters $parameters
     * @param \DateTimeInterface $previousMusicalDate
     * @throws \Exception
     * @see OnParametersChangeTest::testOnMusicalDateChange()
     */
    public function onMusicalDateChange(Parameters $parameters, \DateTimeInterface $previousMusicalDate): void{
        $currentMusicalDate = $parameters->getMusicalDate();

        if($previousMusicalDate > $currentMusicalDate){
            $lowerDate = $currentMusicalDate;
            $higherDate = $previousMusicalDate;
        }else{
            $lowerDate = $previousMusicalDate;
            $higherDate = $currentMusicalDate;
        }

        $startDate = new \DateTime(date('Y') . '-' . $lowerDate->format('m-d'));
        $endDate = new \DateTime(date('Y') . '-' . $higherDate->format('m-d'));

        $coursesToUpdate = $this->courseRepository->getCoursesToFrom($parameters->getOrganization(), $startDate, $endDate);

        /** @var Course $course */
        foreach ($coursesToUpdate as $course){
            $year = $this->organizationUtils->getActivityYearSwitchDate($parameters->getOrganization(), $course->getDatetimeStart());
            $course->setStartYear($year);
            $course->setEndYear($year + 1);
        }
    }
}
