<?php

declare(strict_types=1);

namespace App\Service\Mailer\Builder;

use App\Entity\Access\Access;
use App\Entity\Core\ContactPoint;
use App\Entity\Message\Email as EmailEntity;
use App\Entity\Organization\Organization;
use App\Enum\Core\ContactPointTypeEnum;
use App\Enum\Core\EmailSendingTypeEnum;
use App\Enum\Message\ReportMessageStatusEnum;
use App\Repository\Core\ContactPointRepository;
use App\Service\Mailer\Email;
use App\Service\Mailer\EmailRecipient;
use App\Tests\Unit\Service\Mailer\Builder\AbstractBuilderTest;
use Symfony\Contracts\Service\Attribute\Required;
use Twig\Environment;

/**
 * Classe AbstractBuilder qui définit les fonctions de bases de chaque builder.
 */
class AbstractBuilder implements AbstractBuilderInterface
{
    protected Environment $twig;
    protected ContactPointRepository $contactPointRepository;

    #[Required]
    public function setTwig(Environment $twig): void
    {
        $this->twig = $twig;
    }

    #[Required]
    public function setContactPointRepository(ContactPointRepository $contactPointRepository): void
    {
        $this->contactPointRepository = $contactPointRepository;
    }

    /**
     * @see AbstractBuilderTest::testBuildEmailEntity()
     */
    public function buildEmailEntity(string $subject, Access $author, string $content): EmailEntity
    {
        // todo : on aurait un setAuthor ou pas
        $emailEntity = new EmailEntity();
        /* @phpstan-ignore-next-line Je ne sais pas d'où vient cette erreur, mais elle c'est un faux positif */
        $emailEntity
            ->setAuthor($author)
            ->setIsSystem(true)
            ->setAbout($subject)
            ->setDateSent(new \DateTime('now'))
            ->setText($content)
        ;

        return $emailEntity;
    }

    /**
     * @param mixed[] $context
     *
     * @see AbstractBuilderTest::testRender()
     */
    public function render(string $template, array $context): string
    {
        $templatePath = sprintf('@templates/emails/%s.html.twig', $template);
        return $this->twig->render($templatePath, $context);
    }

    /**
     * @see AbstractBuilderTest::testAddRecipient()
     */
    public function addRecipient(Email $email, Access|Organization|string $target, EmailSendingTypeEnum $sendType, ?ContactPointTypeEnum $contactPointType = null): void
    {
        $emailRecipient = (new EmailRecipient())
            ->setSendType($sendType);

        if ($target instanceof Access) {
            $emailRecipient->setAccess($target);
            $emailRecipient->setName($target->getPerson()->getFullName() ?? $target->getOrganization()->getName());
            $this->setMailToRecipient($this->contactPointRepository->getByTypeAndPerson($contactPointType, $target->getPerson()), $emailRecipient);
        } elseif ($target instanceof Organization) {
            $emailRecipient->setOrganization($target);
            $emailRecipient->setName($target->getName());
            $this->setMailToRecipient($this->contactPointRepository->getByTypeAndOrganization($contactPointType, $target), $emailRecipient);
        } else {
            $emailRecipient->setSendStatus(ReportMessageStatusEnum::DELIVERED);
            $emailRecipient->setEmailAddress($target);
        }

        $email->addEmailRecipient($emailRecipient);
    }

    /**
     * @param list<ContactPoint> $contactPoints
     *
     * @see AbstractBuilderTest::testSetMailToRecipient()
     */
    public function setMailToRecipient(array $contactPoints, EmailRecipient $recipient): void
    {
        if ($contactPoint = $this->getFirstContactPointWithEmail($contactPoints)) {
            $recipient->setSendStatus(ReportMessageStatusEnum::DELIVERED);
            $recipient->setEmailAddress($contactPoint->getEmail());
        } else {
            $recipient->setSendStatus(ReportMessageStatusEnum::MISSING);
        }
    }

    /**
     * @param array<ContactPoint> $contactPoints
     *
     * @see AbstractBuilderTest::testGetFirstContactPointWithEmail()
     */
    public function getFirstContactPointWithEmail(array $contactPoints): ?ContactPoint
    {
        $find = false;
        $cmpt = 0;
        $contactPoint = null;

        while (count($contactPoints) > $cmpt && !$find) {
            if ($contactPoints[$cmpt]->getEmail()) {
                $find = true;
                $contactPoint = $contactPoints[$cmpt];
            }
            ++$cmpt;
        }

        return $contactPoint;
    }
}
