<?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\AccompanyingPeriod\Lifecycle;

use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodInfoRepositoryInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Messenger\MessageBusInterface;

/**
 * Gather all the accompanying period which needs a change in step.
 */
class AccompanyingPeriodStepChangeRequestor
{
    private readonly \DateInterval $intervalForShortInactive;

    private readonly \DateInterval $intervalForLongInactive;

    private readonly bool $isMarkInactive;

    public function __construct(
        private readonly AccompanyingPeriodInfoRepositoryInterface $accompanyingPeriodInfoRepository,
        private readonly LoggerInterface $logger,
        private readonly MessageBusInterface $messageBus,
        ParameterBagInterface $parameterBag,
    ) {
        $config = $parameterBag->get('chill_person')['accompanying_period_lifecycle_delays'];
        $this->isMarkInactive = $config['mark_inactive'];
        $this->intervalForShortInactive = new \DateInterval($config['mark_inactive_short_after']);
        $this->intervalForLongInactive = new \DateInterval($config['mark_inactive_long_after']);
    }

    public function __invoke(): void
    {
        if (!$this->isMarkInactive) {
            return;
        }

        // get the oldest ones first
        foreach (
            $olders = $this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdInactiveAfter(
                $this->intervalForLongInactive,
                [AccompanyingPeriod::STEP_CONFIRMED, AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT]
            ) as $accompanyingPeriodId
        ) {
            $this->logger->debug('request mark period as inactive_short', ['period' => $accompanyingPeriodId]);
            $this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_inactive_long'));
        }

        // the newest
        foreach (
            $this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdInactiveAfter(
                $this->intervalForShortInactive,
                [AccompanyingPeriod::STEP_CONFIRMED]
            ) as $accompanyingPeriodId
        ) {
            if (in_array($accompanyingPeriodId, $olders, true)) {
                continue;
            }

            $this->logger->debug('request mark period as inactive_long', ['period' => $accompanyingPeriodId]);
            $this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_inactive_short'));
        }

        // a new event has been created => remove inactive long, or short
        foreach (
            $this->accompanyingPeriodInfoRepository->findAccompanyingPeriodIdActiveSince(
                $this->intervalForShortInactive,
                [AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT, AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG]
            ) as $accompanyingPeriodId
        ) {
            $this->logger->debug('request mark period as active', ['period' => $accompanyingPeriodId]);
            $this->messageBus->dispatch(new AccompanyingPeriodStepChangeRequestMessage($accompanyingPeriodId, 'mark_active'));
        }
    }
}
