<?php 

namespace NPS\DependencyInjection;

use Swift_Mailer;
use Swift_Message;
use NPS\Etc\Files;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Lazy sending mailer with template rendering and dev output
 * @author Lukas Korinek
 */
final class Mailer 
{
    /** @var Swift_Mailer $swift */
    private $swift;

    /** @var EngineInterface $twig */
    private $twig;

    /** @var string $outputPath */
    private $outputPath;

    /** @var string $mailFrom */
    private $mailFrom;

    /** @var array $mailSubjectTranslations */
    private $mailSubjectTranslations;

    /** @var array $memory */
    private $memory;

    /** @var string $locale */
    private $locale;

    public function __construct(RequestStack $stack, Swift_Mailer $swift, EngineInterface $twig, array $mailSubjectTranslations, $locale, $mailOutputPath, $mailFrom)
    {
        $this->outputPath = Files::normalizeDirectory($mailOutputPath, Files::WRITEABLE, true);
        $this->swift = $swift;
        $this->twig = $twig;
        $this->mailFrom = $mailFrom;
        $this->mailSubjectTranslations = $mailSubjectTranslations;
        $this->memory = [];
        
        $request = $stack->getCurrentRequest();
        $this->locale = $request ? $request->getLocale() : $locale;
    }

    /**
     * Creates a mail and stores it in memory
     * @param string $recipient Address to which the email should be sent
     * @param string $subject Email subject - nonlocalised, see config for subject translations
     * @param string $template Twig template to use
     * @param string $data Data to be added into twig template
     */
    public function mail($recipient, $subject, $template, $data)
    {
        $subject = trim($this->mailSubjectTranslations[$subject][$this->locale]) ?: $subject;
        $body = $this->twig->render($template, array_merge($data, [
            'locale' => $this->locale,
            'subject' => $subject,
            'year' => date('Y')
        ]));
        

        $this->memory[] = [trim($recipient), $subject, $body];
    }

    /**
     * Commits all mails and sends them
     */
    public function sendAll()
    {
        while(!empty($this->memory))
        {
            $mail = array_shift($this->memory);
            $this->send($mail);
        }
    }

    /**
     * Sends an individual email
     * @param array $mail Memory mail data
     */
    private function send(array $mail)
    {
        list($recipient, $subject, $body) = $mail;

        // Send mail message
        $message = (new Swift_Message($subject))
        ->setFrom($this->mailFrom)
        ->setTo($recipient)
        ->setBody($body, 'text/html');

        $this->swift->send($message);

        // Save preview
        $subfolder = $this->outputPath . '/' . str_replace('@', '_at_', $recipient);
        $subfolder = Files::normalizeDirectory($subfolder, Files::WRITEABLE, true);
        $filename = $subfolder . '/' . date('dmYHis') . '.html';
        file_put_contents($filename, $body);
    }

    /**
     * Checks if there are any mails waiting to be sent
     * @return bool
     */
    public function has()
    {
        return !empty($this->memory);
    }

    /**
     * Clears all pending mails from memory
     */
    public function clear()
    {
        $this->memory = [];
    }
}

