<?php

namespace Velis\Mail\Transport;

use Aws\Ses\SesClient;
use Velis\App;
use Velis\Bpm\Email\Account;
use Velis\Mail\Mail;
use Velis\Model\BaseModel;

/**
 * @author Daniel Zaucha <daniel.zaucha@velis.pl>
 */
class AwsSes extends BaseModel
{
    /**
     * Message containing all necessary data
     * @var array
     */
    protected $_message;

    /**
     * Ses instance
     * @var SesClient
     */
    protected static $_sesClient;

    /**
     * Class constructor
     */
    public function __construct()
    {
        self::createInstance();
    }

    private static function createInstance()
    {
        if (!self::$_sesClient) {
            self::$_sesClient = new SesClient([
                'version' => '2010-12-01',
                'region'  => App::$config->notifications->aws->sesRegion,
                'credentials' => [
                    'key' => App::$config->notifications->aws->userAccessKeyID,
                    'secret' => App::$config->notifications->aws->userSecretAccessKey
                ]
            ]);
        }
    }

    public function send($mail)
    {
        //SDK method allows max 50 recipients at single call
        $maxRecipientsInSingleCall = 50;
        $this->prepareMessage($mail);

        if (empty(array_filter($this->_message['bccAddresses']))) {
            $this->_message['bccAddresses'] = [];
        }

        if (empty(array_filter($this->_message['ccAddresses']))) {
            $this->_message['ccAddresses'] = [];
        }

        if (empty(array_filter($this->_message['toAddresses']))) {
            $this->_message['toAddresses'] = [];
        }

        $destinations = array_merge($this->_message['bccAddresses'], $this->_message['ccAddresses'], $this->_message['toAddresses']);
        if (count($destinations) <= $maxRecipientsInSingleCall) {
            $this->performSend($destinations);
        } else {
            foreach (array_chunk($destinations, $maxRecipientsInSingleCall) as $recipientsChunk) {
                $this->performSend($recipientsChunk);
            }
        }
    }

    /**
     * Perform raw mail send through AWS SDK
     *
     * @param string[] $destinations
     */
    protected function performSend($destinations)
    {
        $mailObj = [
            'Destinations' => $destinations,
            'ReplyToAddresses' => [$this->_message['sender']],
            'Source' => $this->_message['sender'],
            'RawMessage' => [
                'Data' => $this->_message['plainBody']
            ]
        ];

        self::$_sesClient->sendRawEmail($mailObj);
    }

    /**
     * Prepares message object
     *
     * @param Mail $mail
     */
    protected function prepareMessage($mail)
    {
        foreach ($mail->getTo() as $address) {
            $to[] = $address->getEmail();
        }

        foreach ($mail->getCc() as $address) {
            $cc[] = $address->getEmail();
        }

        foreach ($mail->getBcc() as $address) {
            $bcc[] = $address->getEmail();
        }

        $this->_message = [
            'plainBody' => $mail->toString(),
            'sender'    => ($mail->getSender() ?: App::$config->notifications->emailFrom),
            'toAddresses' => $to,
            'bccAddresses' => $bcc,
            'ccAddresses' => $cc,
            'subject'   => $mail->getSubject(),
        ];
    }

    /**
     * @return bool
     */
    public static function isEnabled(): bool
    {
        $config = App::$config->notifications->aws;

        return $config && App::$config->notifications->aws->sesEnabled;
    }

    /**
     * Checks for email sending availability through SES service
     *
     * @param Account $emailAccount
     * @return bool
     */
    public static function checkForSendingAvailability($emailAccount)
    {
        if (!$emailAccount) {
            $emailAccount = Account::byEmail(App::$config->notifications->emailFrom);
        }

        return self::isEnabled() && $emailAccount && $emailAccount->aws_ses;
    }

    /**
     * Checks if email's domain is verified in AWS console
     *
     * @param string $email
     * @return bool
     */
    public static function isEmailVerified($email)
    {
        self::createInstance();
        $result = self::$_sesClient->listIdentities([
            'IdentityType' => 'Domain',
            'MaxItems' => 10
        ]);

        $domain = substr($email, strpos($email, '@') + 1);

        return in_array($domain, $result['Identities']);
    }
}
