<?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\Service\DocGenerator;

use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithAdminFormInterface;
use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithPublicFormInterface;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Context to generate a document with a destinee (i.e. generate a letter).
 */
class PersonContextWithThirdParty implements DocGeneratorContextWithAdminFormInterface, DocGeneratorContextWithPublicFormInterface
{
    public function __construct(
        private readonly PersonContextInterface $personContext,
        private readonly NormalizerInterface $normalizer,
        private readonly ThirdPartyRepository $thirdPartyRepository,
    ) {}

    public function adminFormReverseTransform(array $data): array
    {
        return array_merge(
            $this->personContext->adminFormReverseTransform($data),
            ['label' => $data['label']]
        );
    }

    public function adminFormTransform(array $data): array
    {
        return array_merge(
            $this->personContext->adminFormTransform($data),
            ['label' => $data['label'] ?? '']
        );
    }

    public function buildAdminForm(FormBuilderInterface $builder): void
    {
        $this->personContext->buildAdminForm($builder);

        $builder->add('label', TextType::class, [
            'label' => 'docgen.Label for third party',
            'required' => true,
        ]);
    }

    public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void
    {
        $this->personContext->buildPublicForm($builder, $template, $entity);

        $builder->add('thirdParty', PickThirdpartyDynamicType::class, [
            'multiple' => false,
            'label' => $template->getOptions()['label'] ?? 'ThirdParty',
            'validation_groups' => ['__none__'],
        ]);
    }

    public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
    {
        $data = $this->personContext->getData($template, $entity, $contextGenerationData);

        $data['thirdParty'] = $this->normalizer->normalize(
            $contextGenerationData['thirdParty'],
            'docgen',
            ['docgen:expects' => ThirdParty::class, 'groups' => ['docgen:read']]
        );

        return $data;
    }

    public function getDescription(): string
    {
        return 'docgen.A context for person with a third party (for sending mail)';
    }

    public function getEntityClass(): string
    {
        return $this->personContext->getEntityClass();
    }

    public function getFormData(DocGeneratorTemplate $template, $entity): array
    {
        return $this->personContext->getFormData($template, $entity);
    }

    public static function getKey(): string
    {
        return self::class;
    }

    public function getName(): string
    {
        return 'docgen.Person with third party';
    }

    public function hasAdminForm(): bool
    {
        return true;
    }

    public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool
    {
        return true;
    }

    public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
    {
        return array_merge(
            [
                'thirdParty' => null === $data['thirdParty'] ? null : $data['thirdParty']->getId(),
            ],
            $this->personContext->contextGenerationDataNormalize($template, $entity, $data),
        );
    }

    public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
    {
        return array_merge(
            [
                'thirdParty' => null === $data['thirdParty'] ? null : $this->thirdPartyRepository->find($data['thirdParty']),
            ],
            $this->personContext->contextGenerationDataDenormalize($template, $entity, $data),
        );
    }

    public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
    {
        $this->personContext->storeGenerated($template, $storedObject, $entity, $contextGenerationData);
    }
}
