<?php


namespace Diamond\Application\Mailing;

use Core\MailingPreparation\MailingCook;
use Core\TwigAwareInterface;
use Core\TwigAwareTrait;
use Diamond\Config\Main;
use Diamond\Domain\MailingList\Concrete\MailingListEntityInterface;
use Diamond\Domain\MailingList\MailingListCollection;
use Diamond\Application\Mailing\Exceptions\MailingException;
use Diamond\Application\Mailing\Exceptions\MailingListNotFoundException;
use Diamond\Helpers\Date;
use Diamond\Infrastructure\Models\MailingRequest\MailingRequest;
use Diamond\Infrastructure\Models\MailingRequestRecipient\MailingRequestRecipient;
use Diamond\Repositories\MailingList\MailingListCriteria;
use Diamond\Repositories\MailingList\MailingListRepository;
use Diamond\Repositories\MailingRequestRecipient\MailingRequestRecipientRepository;
use Diamond\Repositories\MailingSubscriber\MailingSubscriberRepository;
use Diamond\Repositories\MailingTemplate\MailingTemplateRepository;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;

/**
 * Бизнес процессы рассылки
 * Class Mailing
 * @package Diamond\UseCases\Mailing
 */
class MailingService implements LoggerAwareInterface, TwigAwareInterface
{
    use LoggerAwareTrait;
    use TwigAwareTrait;


    public function __construct(private MailingListRepository       $mailingListRepository,
                                private MailingSubscriberRepository $mailingSubscriberRepository,
                                private MailingRequestRecipientRepository $mailingRequestRecipientRepository,
                                private MailingTemplateRepository   $mailingTemplateRepository,
                                private MailingCook                 $mailingCook,
                                private Main $mainConfig,
                                private MailingRecipientsCollection $mailingRecipientsCollection
    )
    {
    }

    /**
     * @return MailingRequestRecipientRepository
     */
    public function getMailingRequestRecipientRepository(): MailingRequestRecipientRepository
    {
        return $this->mailingRequestRecipientRepository;
    }


    /**
     * @return MailingListRepository
     */
    public function getMailingListRepository(): MailingListRepository
    {
        return $this->mailingListRepository;
    }

    /**
     * @return MailingSubscriberRepository
     */
    public function getMailingSubscriberRepository(): MailingSubscriberRepository
    {
        return $this->mailingSubscriberRepository;
    }

    /**
     * @return MailingTemplateRepository
     */
    public function getMailingTemplateRepository(): MailingTemplateRepository
    {
        return $this->mailingTemplateRepository;
    }


    /**
     * получение листа рассылки
     * @param int $id
     * @return MailingListEntityInterface
     */
    public function getMailingList(int $id): MailingListEntityInterface
    {
        if (!$mailing = $this->mailingListRepository->findById($id)) {
            throw new MailingListNotFoundException(sprintf(
                'mailing list not found by id `%s`', $id
            ));
        }
        return $mailing;
    }

    /**
     * @param MailingListEntityInterface $mailingListEntity
     * @param string|null $email
     * @param string|null $key
     * @return string
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\SyntaxError
     */
    public function getMailingListBodyForSubscriber(
        MailingListEntityInterface $mailingListEntity,
        string                     $email = null,
        string                     $key = null
    ): string
    {
        $key = $key ?? md5($email);

        $subscribeEmails = $this->getSubscribeEmails($mailingListEntity);

        $email = $email ?? $subscribeEmails[array_rand($subscribeEmails)];

        $template = $mailingListEntity->getMailingTemplate();

        $body = $template->getBody();

        if(!empty($template->getbodyFile())){

            $data = $this->getSubscribeDataByEmail($mailingListEntity, $email);

            $body = $this->twig->render($template->getbodyFile(), array_merge($data,[
                'email' => $email,
                'site' => getenv('BASE_URL'),
                'body' => $this->twig->createTemplate( $body)->render($data),
                'date_short' => date('d'). ' ' . Date::rusMonth(time()),
                'date' => date('d'). ' ' . Date::rusMonth(time()).' '.date('Y'),
                'copyright' => $this->mainConfig->getCopyright(),
                'signature' => $this->mainConfig->getSignature()
            ]));
        }

        $body = $this->mailingCook->prepare($body, $key);

        return $body;
    }


    public function getSubscribeDataByEmail(MailingListEntityInterface $mailingListEntity, string $email): array
    {

        $sub = $mailingListEntity->getMailingSubscriber();

        foreach ($this->mailingRecipientsCollection->getHandlers() as $mailingRecipients) {

            if (get_class($mailingRecipients) === $sub->getFn()) {
                return $mailingRecipients->getDataFromEmail($email);
            }
        }

        return [];
    }


    /**
     * @param MailingListEntityInterface $mailingListEntity
     * @return array
     */
    public function getSubscribeEmails(MailingListEntityInterface $mailingListEntity): array
    {
        $emails = [];

        $sub = $mailingListEntity->getMailingSubscriber();


        foreach ($this->mailingRecipientsCollection->getHandlers() as $mailingRecipients) {
            if (get_class($mailingRecipients) === $sub->getFn()) {
                $emails = $mailingRecipients->getMails();
            }
        }

        $_emails = explode(';', $sub->getCustomMails());

        $_emails = array_merge($emails, $_emails);

        $_ignore = explode(';', $sub->getIgnoreMails());

        array_walk($_emails,function (&$email){
            $email = trim($email);
        });

        array_walk($_ignore,function (&$email){
            $email = trim($email);
        });

        $emails = \array_diff($_emails, $_ignore);

        return array_unique($emails);
    }


    /**
     * Запуск рассылки, перевод в рабочее состояние
     * @todo в методе не работает блок $recipients, возможно рудемент??
     * @param MailingListEntityInterface $mailingListEntity
     */
    public function sendMailing(MailingListEntityInterface $mailingListEntity): void
    {

        $template = $mailingListEntity->getMailingTemplate();

        $body = $template->getBody();
        $subject = $template->getSubject();


        try {

            $request = (new MailingRequest())
                ->setBody($body)
                ->setSubject($subject)
                ->setMailingId($mailingListEntity->getId());

            $emails = $this->getSubscribeEmails($mailingListEntity);
            $emailsTo = [];

            if (!count($emails)) {
                throw new MailingException('receipts not set');
            }

            foreach ($emails as $mail) {
                $recipients = (new MailingRequestRecipient())
                    ->setMailingRequest($request)
                    ->setEmail($mail);
            }

            $request->save();

        } catch (\RuntimeException $exception) {
            $this->logger->error($exception->getMessage());
            throw new MailingException('send mailing error');
        }
    }


    /**
     * @return MailingListCollection
     * @throws \Repo\Concrete\Exceptions\Collection
     */
    public function getActiveMailing(?int $limit = null): MailingListCollection
    {
        $criteria = MailingListCriteria::create()->setFilterByActive(true)->setSortById('DESC');

        if($limit){
            $criteria->setLimit($limit);
        }

        return $this->mailingListRepository->findByCriteria(
            $criteria
        );
    }

    /**
     * @return array
     * Формировать динамически список вариантов подписки
     */
    public function getRules()
    {
        $rules = [
            'custom' => 'любые адреса',
        ];

        $items = $this->mailingRecipientsCollection->getHandlers();

        foreach ($items as $item) {
            $rules[get_class($item)] = $item->getName();
        }

        return $rules;

//        return [
//            'allUsers'      => 'Система / Все пользователи',
//            'allClients'      => 'Магазин / Все клиенты',
////            'group3ClientsOffice1'      => 'Магазин / 3-я Группа клиентов, офис 1',
//            'blockClients'    => 'Магазин / Заблокированные клиенты',
//            'noneAuthClients' => 'Магазин / Неавторизованные клиенты',
//            'AuthClients'     => 'Магазин / Авторизованные клиенты',
//            'custom' => 'любые адреса',
//        ];
    }
}