<?php
/**
 * Copyright (c) 2017 Serhii Borodai <clarifying@gmail.com>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *
 */

namespace App\Service;


use App\Authentication\Tokenizer\Confirmation;
use App\Entity\ApplyVacancy;
use App\Entity\Feedback;
use App\Entity\IdentityInterface;
use App\Entity\User;
use Monolog\Logger;
use Zend\Expressive\Template\TemplateRendererInterface;
use Zend\Hydrator\DelegatingHydrator;
use Zend\Mail\Message;
use Zend\Mail\Transport\Smtp;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\Mime;
use Zend\Mime\Part;

/**
 * Class Mailer
 * @todo if we want to send thousands of letters, it is necessary to use queue with delayed mail sending
 *
 * @package App\Model
 */
class Mailer
{

    const MAIL_FOR_FEEDBACK = 'feedback';
    const MAIL_NO_REPLY = 'no-reply';
    const MAIL_APPLY_VACANCY = 'apply vacancy';

    /**
     * @var TemplateRendererInterface
     */
    protected $template;

    /**
     * @var Smtp
     */
    protected $transport;

    /**
     * @var Confirmation
     */
    protected $tokenizer;

    /**
     * @var DelegatingHydrator
     */
    protected $hydrator;

    /**
     * @var array
     */
    protected $mails;
    /**
     * @var Logger
     */
    protected $log;

    /**
     * Mailer constructor.
     * @param Smtp $transport
     * @param TemplateRendererInterface $template
     * @param Confirmation $tokenizer
     * @param DelegatingHydrator $hydrator
     * @param array $mails
     * @throws \Exception
     */
    public function __construct(Smtp $transport, TemplateRendererInterface $template, Confirmation $tokenizer, DelegatingHydrator $hydrator, array $mails, Logger $logger)
    {
        $this->transport = $transport;
        $this->template = $template;
        $this->tokenizer = $tokenizer;
        $this->hydrator = $hydrator;
        $this->log = $logger;

        if (!isset($mails[self::MAIL_FOR_FEEDBACK])) {
            throw new \Exception('Mail address for feedback not set. Check config');
        }
        if (!isset($mails[self::MAIL_NO_REPLY])) {
            throw new \Exception('Mail address for no-reply not set. Check config');
        }
        if (!isset($mails[self::MAIL_APPLY_VACANCY])) {
            throw new \Exception('Mail address for vacancy applying not set. Check config');
        }
        $this->mails = $mails;
    }

    /**
     * @param IdentityInterface|User $entity
     * @param $lang
     */
    public function sendActivationMail(IdentityInterface $entity, $lang)
    {
        $mail = $this->transport;
        $message = new Message();

        $message->setTo($entity->getEmail())
            ->setFrom($this->mails[self::MAIL_NO_REPLY])
            ->setSubject('Your AddCPM account: Email address verification' . ' / ' .
                _t('Your AddCPM account: Email address verification'))
        ;

        $activationToken = $this->tokenizer->encode($this->hydrator->extract($entity));

        $htmlContent = $this->template->render('app::mail/activation', [
            'layout' => 'empty',
            'lang' => $lang,
            'activationToken' => $activationToken
        ]);
        $mimeMessage = new MimeMessage();

        $mimeMessage->setParts([
            (new Part()) // html message
            ->setCharset('UTF-8')
                ->setType(Mime::TYPE_HTML)
                ->setContent($htmlContent),
        ]);

        $message->setBody($mimeMessage);

        try {
            $mail->send($message);
        } catch (\Exception $e) {
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
        }

    }

    /**
     * @param User $user
     * @param string $pass
     */
    public function sendRestorePassword(User $user, string $pass, $lang)
    {
        $mail = $this->transport;
        $message = new Message();
        $message->setTo($user->getEmail())
            ->setFrom($this->mails[self::MAIL_NO_REPLY])
            ->setSubject('Your AddCPM account: reset password' . ' / ' .
                _t('Your AddCPM account: reset password'))
        ;

        $htmlContent = $this->template->render('app::mail/password-reset', [
            'layout' => 'empty',
            'lang' => $lang,
            'user' => $user,
            'pass' => $pass,
        ]);
        $mimeMessage = new MimeMessage();

        $mimeMessage->setParts([
            (new Part()) // html message
            ->setCharset('UTF-8')
                ->setType(Mime::TYPE_HTML)
                ->setContent($htmlContent),
        ]);

        $message->setBody($mimeMessage);

        try {
            $mail->send($message);
        } catch (\Exception $e) {
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
        }
    }

    /**
     * @param Feedback $feedback
     */
    public function sendFeedback(Feedback $feedback)
    {
        $message = new Message();
        $message->setTo($this->mails[self::MAIL_FOR_FEEDBACK])
            ->setFrom($this->mails[self::MAIL_NO_REPLY])
            ->setReplyTo($feedback->getEmail(), '=?utf-8?B?'.base64_encode($feedback->getName()).'?=')
            ->setSubject('Contacts page')
            ->setBody(
                'Name: ' . $feedback->getName() . PHP_EOL .
                'Mail from: ' . $feedback->getEmail() . PHP_EOL .
                str_repeat('=', 10) . PHP_EOL .
                htmlentities($feedback->getMessage())
            );

        try {
            $this->transport->send($message);
        } catch (\Exception $e) {
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
        }
    }

    /**
     * @param ApplyVacancy $applyVacancy
     * @param Item $vacancy
     */
    public function sendApplyVacancy(ApplyVacancy $applyVacancy, Item $vacancy)
    {
        $message = new Message();
        $message->setTo($this->mails[self::MAIL_APPLY_VACANCY])
            ->setFrom($this->mails[self::MAIL_NO_REPLY])
            ->setSubject('Apply vacancy ID:' . $vacancy->getId() . '"' . $vacancy->getTitle())
            ->setBody(
                'Vacancy ID:' . $vacancy->getId() . '"' . $vacancy->getTitle() . PHP_EOL .
                'Name : ' . $applyVacancy->getName() . PHP_EOL .
                'Phone : ' . $applyVacancy->getPhone() . PHP_EOL .
                'Mail : ' . $applyVacancy->getMail() . PHP_EOL
            );

        try {
            $this->transport->send($message);
        } catch (\Exception $e) {
            var_dump('here');die();
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
        }
    }

    /**
     * @param string $name
     * @param string $phone
     * @param string $mail
     * @param string $uuid
     */
    public function sendActivateProtectionRequest($name, $phone, $mail, $uuid)
    {
        $message = new Message();
        $message->setTo($this->mails[self::MAIL_FOR_FEEDBACK])
            ->setFrom($this->mails[self::MAIL_NO_REPLY])
            ->setSubject('Request to activate protection')
            ->setBody(
                'Name : ' . $name . PHP_EOL .
                'Phone : ' . $phone . PHP_EOL .
                'Mail : ' . $mail . PHP_EOL .
                'UUID : ' . $uuid . PHP_EOL
            );

        try {
            $this->transport->send($message);
        } catch (\Exception $e) {
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
        }
    }
}