<?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\ActivityBundle\Export\Export\LinkedToACP;

use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Export\Export\ListActivityHelper;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\PersonBundle\Export\Helper\FilterListAccompanyingPeriodHelperInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\FormBuilderInterface;

final readonly class ListActivity implements ListInterface, GroupedExportInterface
{
    public function __construct(
        private ListActivityHelper $helper,
        private EntityManagerInterface $entityManager,
        private TranslatableStringExportLabelHelper $translatableStringExportLabelHelper,
        private FilterListAccompanyingPeriodHelperInterface $filterListAccompanyingPeriodHelper,
    ) {}

    public function buildForm(FormBuilderInterface $builder)
    {
        $this->helper->buildForm($builder);
    }

    public function getNormalizationVersion(): int
    {
        return 1;
    }

    public function normalizeFormData(array $formData): array
    {
        return [];
    }

    public function denormalizeFormData(array $formData, int $fromVersion): array
    {
        return [];
    }

    public function getFormDefaultData(): array
    {
        return [];
    }

    public function getAllowedFormattersTypes()
    {
        return $this->helper->getAllowedFormattersTypes();
    }

    public function getDescription()
    {
        return ListActivityHelper::MSG_KEY.'List activities linked to an accompanying course';
    }

    public function getGroup(): string
    {
        return 'Exports of activities linked to an accompanying period';
    }

    public function getLabels($key, array $values, $data)
    {
        return match ($key) {
            'acpId' => static function ($value) {
                if ('_header' === $value) {
                    return ListActivityHelper::MSG_KEY.'accompanying course id';
                }

                return $value ?? '';
            },
            'scopesNames' => $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY.'course circles'),
            default => $this->helper->getLabels($key, $values, $data),
        };
    }

    public function getQueryKeys($data): array
    {
        return
            array_merge(
                $this->helper->getQueryKeys($data),
                [
                    'acpId',
                    'scopesNames',
                ]
            );
    }

    public function getResult($query, $data, ExportGenerationContext $context): array
    {
        return $this->helper->getResult($query, $data);
    }

    public function getTitle(): string|\Symfony\Contracts\Translation\TranslatableInterface
    {
        return ListActivityHelper::MSG_KEY.'List activity linked to a course';
    }

    public function getType(): string
    {
        return $this->helper->getType();
    }

    public function initiateQuery(array $requiredModifiers, array $acl, array $data, ExportGenerationContext $context): \Doctrine\ORM\QueryBuilder
    {
        $qb = $this->entityManager->createQueryBuilder();

        $qb
            ->distinct()
            ->from(Activity::class, 'activity')
            ->join('activity.accompanyingPeriod', 'acp')
            ->leftJoin('acp.participations', 'acppart')
            ->leftJoin('acppart.person', 'person')
            ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL');

        $this->filterListAccompanyingPeriodHelper->addFilterAccompanyingPeriods($qb, $requiredModifiers, $acl, $context->byUser, $data);

        $qb
            // some grouping are necessary
            ->addGroupBy('acp.id')
            ->addOrderBy('activity.date')
            ->addOrderBy('activity.id');

        $this->helper->addSelect($qb);

        // add select for this step
        $qb
            ->addSelect('acp.id AS acpId')
            ->addSelect('(SELECT AGGREGATE(acpScope.name) FROM '.Scope::class.' acpScope WHERE acpScope MEMBER OF acp.scopes) AS scopesNames')
            ->addGroupBy('scopesNames');

        AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);

        return $qb;
    }

    public function requiredRole(): string
    {
        return ActivityStatsVoter::LISTS;
    }

    public function supportsModifiers()
    {
        return array_merge(
            $this->helper->supportsModifiers(),
            [
                Declarations::ACTIVITY,
                \Chill\PersonBundle\Export\Declarations::ACP_TYPE,
            ]
        );
    }
}
