<?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\Workflow;

use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Workflow\WorkflowWithPublicViewDocumentHelper;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithPublicViewInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface;
use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkEvaluationDocumentVoter;
use Chill\PersonBundle\Service\AccompanyingPeriodWork\ProvidePersonsAssociated;
use Chill\PersonBundle\Service\AccompanyingPeriodWork\ProvideThirdPartiesAssociated;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * @implements EntityWorkflowWithStoredObjectHandlerInterface<AccompanyingPeriodWorkEvaluationDocument>
 */
class AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler implements EntityWorkflowWithStoredObjectHandlerInterface, EntityWorkflowWithPublicViewInterface
{
    public function __construct(
        private readonly AccompanyingPeriodWorkEvaluationDocumentRepository $repository,
        private readonly EntityWorkflowRepository $workflowRepository,
        private readonly TranslatableStringHelperInterface $translatableStringHelper,
        private readonly TranslatorInterface $translator,
        private readonly WorkflowWithPublicViewDocumentHelper $publicViewDocumentHelper,
        private readonly ProvideThirdPartiesAssociated $provideThirdPartiesAssociated,
        private readonly ProvidePersonsAssociated $providePersonsAssociated,
    ) {}

    public function getDeletionRoles(): array
    {
        return [
            '_',
        ];
    }

    public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array
    {
        $doc = $this->getRelatedEntity($entityWorkflow);

        if (null === $doc) {
            return [
                'persons' => [],
            ];
        }

        return [
            'persons' => $doc->getAccompanyingPeriodWorkEvaluation()
                ->getAccompanyingPeriodWork()->getPersons(),
        ];
    }

    public function getEntityTitle(EntityWorkflow $entityWorkflow, array $options = []): string
    {
        $doc = $this->getRelatedEntity($entityWorkflow);

        if (null === $doc) {
            return $this->translator->trans('workflow.doc for evaluation deleted');
        }

        return $this->translator->trans(
            'entity_display_title.Doc for evaluation (n°%eval%)',
            ['%eval%' => $entityWorkflow->getRelatedEntityId()]
        ).' ('.$this->translatableStringHelper->localize($doc->getAccompanyingPeriodWorkEvaluation()
            ->getEvaluation()->getTitle()).') '.$doc->getTitle();
    }

    public function getRelatedEntity(EntityWorkflow $entityWorkflow): ?AccompanyingPeriodWorkEvaluationDocument
    {
        return $this->repository->find($entityWorkflow->getRelatedEntityId());
    }

    public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
    {
        return $this->getRelatedEntity($entityWorkflow)?->getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork()
            ->getAccompanyingPeriod();
    }

    /**
     * @return array[]
     */
    public function getRelatedObjects(object $object): array
    {
        return [
            ['entityClass' => AccompanyingPeriodWorkEvaluationDocument::class, $object->getId()],
        ];
    }

    public function getRoleShow(EntityWorkflow $entityWorkflow): ?string
    {
        return AccompanyingPeriodWorkEvaluationDocumentVoter::SEE;
    }

    public function getSuggestedUsers(EntityWorkflow $entityWorkflow): array
    {
        $related = $this->getRelatedEntity($entityWorkflow);

        if (null === $related) {
            return [];
        }

        $users = [];
        if (null !== $referrer = $related->getAccompanyingPeriodWorkEvaluation()
            ->getAccompanyingPeriodWork()
            ->getAccompanyingPeriod()
            ->getUser()
        ) {
            $users[] = $referrer;
        }

        foreach ($related->getAccompanyingPeriodWorkEvaluation()
            ->getAccompanyingPeriodWork()
            ->getReferrersHistoryCurrent() as $referrerHistory
        ) {
            $users[] = $referrerHistory->getUser();
        }

        return array_values(
            // filter objects to remove duplicates
            array_filter(
                $users,
                fn ($o, $k) => array_search($o, $users, true) === $k,
                ARRAY_FILTER_USE_BOTH
            )
        );
    }

    public function getTemplate(EntityWorkflow $entityWorkflow, array $options = []): string
    {
        return '@ChillPerson/Workflow/_evaluation_document.html.twig';
    }

    public function getTemplateData(EntityWorkflow $entityWorkflow, array $options = []): array
    {
        $doc = $this->getRelatedEntity($entityWorkflow);

        return [
            'entity_workflow' => $entityWorkflow,
            'evaluation' => null !== $doc ? $doc->getAccompanyingPeriodWorkEvaluation() : $doc,
            'doc' => $doc,
        ];
    }

    public function isObjectSupported(object $object): bool
    {
        return $object instanceof AccompanyingPeriodWorkEvaluationDocument;
    }

    public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool
    {
        return AccompanyingPeriodWorkEvaluationDocument::class === $entityWorkflow->getRelatedEntityClass();
    }

    public function getAssociatedStoredObject(EntityWorkflow $entityWorkflow): ?StoredObject
    {
        return $this->getRelatedEntity($entityWorkflow)?->getStoredObject();
    }

    public function supportsFreeze(EntityWorkflow $entityWorkflow, array $options = []): bool
    {
        return false;
    }

    public function findByRelatedEntity(object $object): array
    {
        if (!$object instanceof AccompanyingPeriodWorkEvaluationDocument) {
            return [];
        }

        return $this->workflowRepository->findByRelatedEntity(AccompanyingPeriodWorkEvaluationDocument::class, $object->getId());
    }

    public function renderPublicView(EntityWorkflowSend $entityWorkflowSend, EntityWorkflowViewMetadataDTO $metadata): string
    {
        return $this->publicViewDocumentHelper->render($entityWorkflowSend, $metadata, $this);
    }

    public function getSuggestedPersons(EntityWorkflow $entityWorkflow): array
    {
        $related = $this->getRelatedEntity($entityWorkflow);

        if (null === $related) {
            return [];
        }

        return $this->providePersonsAssociated->getPersonsAssociated($related->getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork());
    }

    public function getSuggestedThirdParties(EntityWorkflow $entityWorkflow): array
    {
        $related = $this->getRelatedEntity($entityWorkflow);

        if (null === $related) {
            return [];
        }

        return $this->provideThirdPartiesAssociated->getThirdPartiesAssociated($related->getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork());
    }
}
