<?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\DataFixtures\ORM;

use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Repository\SocialWork\EvaluationRepository;
use Doctrine\Persistence\ObjectManager;

class LoadAccompanyingPeriodWork extends \Doctrine\Bundle\FixturesBundle\Fixture implements \Doctrine\Common\DataFixtures\DependentFixtureInterface
{
    /**
     * @var array|Evaluation[]
     */
    private array $cacheEvaluations = [];

    public function __construct(private readonly AccompanyingPeriodRepository $periodRepository, private readonly EvaluationRepository $evaluationRepository) {}

    public function getDependencies(): array
    {
        return [
            LoadPeople::class,
        ];
    }

    public function load(ObjectManager $manager): void
    {
        // load all the period which are confirmed
        $periods = $this->periodRepository
            ->findBy(['step' => AccompanyingPeriod::STEP_CONFIRMED]);

        $i = 0;

        while (null !== $period = \array_pop($periods)) {
            /* @var AccompanyingPeriod $period */
            ++$i;

            if (0 === $i % 15) {
                $manager->flush();
            }

            if (0 === $period->getSocialIssues()->count()) {
                continue;
            }
            $work = new AccompanyingPeriod\AccompanyingPeriodWork();
            $action = $this->getRandomAction($period->getSocialIssues()->first());

            if (null !== $action) {
                $work
                    ->setAccompanyingPeriod($period)
                    ->setSocialAction($action)
                    ->setStartDate(new \DateTimeImmutable('today'))
                    ->addPerson($period->getPersons()->first())
                    ->setCreatedAt(new \DateTimeImmutable())
                    ->setCreatedBy($this->getReference('center a_social', User::class))
                    ->setUpdatedAt(new \DateTimeImmutable())
                    ->setUpdatedBy($this->getReference('center a_social', User::class));
                $manager->persist($work);

                if ($action->getEvaluations()->count() > 0) {
                    $ev = $action->getEvaluations()->first();
                    $evaluation = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation();
                    $evaluation->setAccompanyingPeriodWork($work)
                        ->setEvaluation($ev);
                    $manager->persist($evaluation);
                }
            }

            // 1 of 10, force an evaluation
            if (0 === $i % 10) {
                $evaluation = $this->getRandomEvaluation();
                $action = $evaluation->getSocialActions()->first();
                $issue = $action->getIssue();

                $period->addSocialIssue($issue);
                $work
                    ->setAccompanyingPeriod($period)
                    ->setSocialAction($action)
                    ->setStartDate(new \DateTimeImmutable('today'))
                    ->addPerson($period->getPersons()->first())
                    ->setCreatedAt(new \DateTimeImmutable())
                    ->setCreatedBy($this->getReference('center a_social', User::class))
                    ->setUpdatedAt(new \DateTimeImmutable())
                    ->setUpdatedBy($this->getReference('center a_social', User::class));
                $manager->persist($work);
                $ev = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation();
                $ev->setAccompanyingPeriodWork($work)
                    ->setEvaluation($evaluation);
                $manager->persist($ev);
            }
        }

        $manager->flush();
    }

    private function getRandomAction(SocialIssue $socialIssue): ?SocialAction
    {
        $actions = $socialIssue->getRecursiveSocialActions()->toArray();

        if (0 === \count($actions)) {
            return null;
        }

        return $actions[\array_rand($actions)];
    }

    private function getRandomEvaluation(): Evaluation
    {
        if (0 === \count($this->cacheEvaluations)) {
            $this->cacheEvaluations = $this->evaluationRepository
                ->findAll();
        }

        return $this->cacheEvaluations[\array_rand($this->cacheEvaluations)];
    }
}
