<?php


namespace Diamond\Console;

use Core\Helpers\Email;
use Diamond\Application\Mailing\MailingService;
use Diamond\Application\Notification\Dto\Message;
use Diamond\Application\Notification\Exceptions\NotificationException;
use Diamond\Application\Notification\NotificationService;
use Diamond\Domain\MailingList\Concrete\MailingListEntityInterface;
use Diamond\Domain\MailingRequestRecipient\Contracts\MailingRequestRecipientEntityInterface;
use Diamond\Factory\Logger;

use Diamond\Infrastructure\Models\MailingRequestRecipient\MailingRequestRecipient;
use Nette\Utils\Validators;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class MailingCommand extends Command implements LoggerAwareInterface
{

    use LoggerAwareTrait;

    protected $mailingService;
    protected $mailingConf;
    protected $notification;

    public function __construct(MailingService $mailingService,
                                \Diamond\Config\Mailing $mailingConf,
                                NotificationService $notification)
    {
        $this->mailingService = $mailingService;
        $this->mailingConf = $mailingConf;
        $this->notification = $notification;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('tools:mailing')->setDescription('Send mailing list');
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int|void
     * @throws \Exception
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {

        $onlyStart = $this->mailingConf->getStartTime();
        $onlyEnd = $this->mailingConf->getEndTime();
        $hour = date('H');
        $access = false;
        if(
            ($onlyStart && $onlyEnd && $hour >= $onlyStart && $hour < $onlyEnd)
            || (!$onlyStart || !$onlyEnd)
        ){
            $access = true;
        }

        if($access === false){
            $output->writeln('пропускаем , стоит ограничение по времени, серверное время: '.date('H:i'));
            return;
        }

        $mailingCollection = $this->mailingService->getActiveMailing();

        $parts = $this->mailingConf->getPartsSend();

        if ($mailingCollection->count() === 0) {
            $output->writeln('send mailing - skip, not ready mails');
        }

        /**
         * @var MailingListEntityInterface $mailing
         */
        foreach ($mailingCollection as $mailing) {

            $this->logger = Logger::buildFileLogger(
                \Monolog\Logger::INFO,
                'mailingLogger',
                'mailing' . $mailing->getId(), 'd_m_Y'
            );


            $part = 0;

            if(!$progressData = $mailing->getProgressData()){
                continue;
            }

            if($progressData->getLastRequest() && $progressData->getLastRequest()->getCompleted() === 1){
                continue;
            }

            $emails = $progressData->getEmails();

            if ($emails->count() === 0) {
                continue;
            }

            /** @var MailingRequestRecipient $recipient */
            foreach ($emails as $recipient) {

                if($recipient->getSendingAt() !== null){
                    continue;
                }

                $mailTo = trim($recipient->getEmail());

                if (false !== Validators::isEmail($mailTo)) {

                    $body = $this->mailingService->getMailingListBodyForSubscriber(
                        $mailing,$mailTo,$recipient->getId()
                    );

                    $message = new Message($progressData->getSubject(),$body);

                    try{
                        $this->notification->sendToEmail($mailTo,$message);
                        $recipient->setSendingAt(new \DateTime());
                        $recipient->setStatus(MailingRequestRecipientEntityInterface::STATUS_SUCCESS);
                        $recipient->save();
                        $this->logger->info(
                            sprintf(
                                'Send mail to %s -  success',
                                $mailTo
                            )
                        );
                    }
                    catch (NotificationException $ex){
                        $this->logger->error($ex->getMessage(), [
                            'email' => $mailTo
                        ]);
                        $output->writeln($ex->getMessage());
                        $recipient->setStatus(MailingRequestRecipientEntityInterface::STATUS_ERROR_SEND);
                        $recipient->save();
                    }

                } else {
                    $m = sprintf(
                        'Mail to %s -  error validate!',
                        $mailTo
                    );
                    $this->logger->error($m);
                    $output->writeln($m);
                    $recipient->setStatus(MailingRequestRecipientEntityInterface::STATUS_NO_VALID);
                    $recipient->save();
                }

                $part++;

                sleep(1);

                if ($part >= $parts) {
                    break;
                }
            }

            if($mailing->getProgressData()->getSending() === $mailing->getProgressData()->getCount()){
                $mailing->completed();
            }

            $m = sprintf(
                'Mailing № %s send success, part %s, %s completed!',
                $mailing->getId(),
                $part,
                $mailing->getProgressData()->getProgress() . '%'
            );

            $output->writeln($m);

            $this->logger->info('Send mailing success!' . $m);
        }


    }
}