<?php

namespace RtmMail\Mailing\Providers;

use Exception;
use Google\Client;
use Google_Service_Gmail;
use Google_Service_Gmail_Message;
use RtmMail\Catcher;
use RtmMail\Helpers\LogHelper;
use RtmMail\Mailing\MailHandler;

class GmailHandler extends MailHandler
{

    private $client;

    public function __construct($logId = 0)
    {
        parent::__construct($logId, 'gmail');

        $this->client = new Client();
        $this->client->setClientId($this->smtpSettings['gmail_client_id'] ?? '');
        $this->client->setClientSecret($this->smtpSettings['gmail_client_secret'] ?? '');
        $this->client->setRedirectUri($this->smtpSettings['gmail_redirect_uri'] ?? '');
        $this->client->addScope("https://www.googleapis.com/auth/gmail.compose");
        $this->client->setAccessType('offline');
        $this->client->setApprovalPrompt('force');

        $this->setTokens();
    }

    public function send()
    {
        $gmail = new Google_Service_Gmail();
        $message = $this->getMessage();
        try {
            $mail = $gmail->users_messages->send("me", $message);
            // Set status on sent and redirect to the log details page
            LogHelper::update($this->logId, ['status' => 'sent', 'sent' => date('Y-m-d H:i:s', time())]);
            do_action('rtmmail_send_success', $this->logId);
            return 'success';
        } catch (Exception $ex) {
            // Set the status to failed and redirect to the log details page
            LogHelper::update($this->logId, ['status' => 'failed', 'sent' => null]);
            do_action('rtmmail_send_failed', $this->logId, $ex->getMessage());
            Catcher::send_text_message($this->logId);
            return $ex->getMessage();
        }
    }

    /**
     * Generate Mime message for the mail
     * @return Google_Service_Gmail_Message
     */
    private function getMessage()
    {
        $message = new Google_Service_Gmail_Message();

        $boundary = uniqid(rand(), true);

        $rawMessage = "From: {$this->attributes['sender_title']} <{$this->attributes['sender_email']}>\r\n";
        $to_addresses = implode(',', $this->attributes['addresses']['to']);
        $rawMessage .= "To: $to_addresses\r\n";
        $cc_addresses = implode(',', $this->attributes['addresses']['cc']);
        $rawMessage .= "Cc: $cc_addresses\r\n";
        $bcc_addresses = implode(',', $this->attributes['addresses']['bcc']);
        $rawMessage .= "Bcc: $bcc_addresses\r\n";

        $rawMessage .= "Subject: =?{$this->attributes['charset']}?B?"
            . base64_encode($this->attributes['subject']) . "?=\r\n";

        $rawMessage .= "MIME-Version: 1.0\r\n";
        $rawMessage .= "Content-type: Multipart/Mixed; boundary=$boundary\r\n";
        $rawMessage .= "\r\n--{$boundary}\r\n";
        $rawMessage .= "Content-Type: {$this->attributes['contentType']}; charset={$this->attributes['charset']}\r\n";
        $rawMessage .= "Content-Transfer-Encoding: quoted-printable\r\n\r\n";

        foreach ($this->attributes['addresses']['to'] as $address) {
            $this->attributes['body'] .= '<img src="' . Catcher::get_track_url($this->logId, $address)  . '" style="display:none;" />';
        }
        $rawMessage .= "{$this->attributes['body']}\r\n";
        $rawMessage .= "--$boundary\r\n";

        foreach ($this->attributes['attachments'] as $attachment) {
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mimeType = finfo_file($finfo, $attachment['path']);
            $fileData = base64_encode(file_get_contents($attachment['path']));

            $rawMessage .= "\r\n--$boundary\r\n";
            $rawMessage .= "Content-Type: $mimeType; name={$attachment['name']}\r\n";
            $rawMessage .= "Content-ID: <{$this->attributes['sender_email']}>\r\n";
            $rawMessage .= "Content-Description: {$attachment['name']}; \r\n";
            $rawMessage .= "Content-Disposition: attachment; filename={$attachment['name']}; size=" . filesize($attachment['path']). ";\r\n";
            $rawMessage .= "Content-Transfer-Encoding: base64\r\n\r\n";
            $rawMessage .= chunk_split($fileData, 76, "\n") . "\r\n";
            $rawMessage .= "--$boundary\r\n";
        }

        $rawMessage = strtr(base64_encode($rawMessage), ['+' => '-', '/' => '_']);

        $message->setRaw($rawMessage);
        return $message;
    }

    public static function getFields()
    {
        return [
            'gmail_client_id' => [
                'type' => 'password',
                'label' => __('Client ID', 'rtm-mail'),
                'description' => __('Gmail API Client ID, you can find this in your Google cloud console under API & Services > Credentials', 'rtm-mail'),
                'key' => 'gmail_client_id',
                'default' => '',
            ],
            'gmail_client_secret' => [
                'type' => 'password',
                'label' => __('Client Secret', 'rtm-mail'),
                'description' => __('Gmail API Secret key, you can find this in your Google cloud console under API & Services > Credentials', 'rtm-mail'),
                'key' => 'gmail_client_secret',
                'default' => '',
            ],
            'gmail_redirect_uri' => [
                'type' => 'text',
                'label' => __('Redirect URI', 'rtm-mail'),
                'description' => __('The authorized redirect URL for the Gmail API.', 'rtm-mail'),
                'key' => 'gmail_redirect_uri',
                'placeholder' => __('Ex. example.com/gmail-api'),
                'default' => '',
            ],
            'gmail_access_token' => [
                'type' => 'hidden',
                'key' => 'gmail_access_token',
                'default' => '',
            ],
            'gmail_refresh_token' => [
                'type' => 'hidden',
                'key' => 'gmail_refresh_token',
                'default' => '',
            ],
            'gmail_token_expires' => [
                'type' => 'hidden',
                'key' => 'gmail_token_expires',
                'default' => 0,
            ],
            'get_gmail_token' => [
                'type' => 'submit',
                'key' => 'get_gmail_token',
                'label' => __('Get Gmail access token', 'rtm-mail'),
                'description' => __('Before using the Gmail API there needs to be an authentication token available. By clicking the button a url will be generated to get this code', 'rtm-mail'),
            ],
            'gmail_auth_code' => [
                'type' => 'text',
                'label' => __('Auth code', 'rtm-mail'),
                'description' => __('The authentication code from Google, please click the button above to generate one (this can be empty ones generated).', 'rtm-mail'),
                'key' => 'gmail_auth_code',
                'placeholder' => __('Auth code'),
                'default' => '',
            ],
        ];
    }

    private function setTokens()
    {
        $tokens = [
            'access_token' => $this->smtpSettings['gmail_access_token'],
            'refresh_token' => $this->smtpSettings['gmail_refresh_token'],
            'expires_in' => $this->smtpSettings['gmail_token_expires'],
        ];

        $this->client->setAccessToken($tokens);

        if ($this->client->isAccessTokenExpired()) {
            if ($this->client->getRefreshToken()) {
                // Set access token with refresh token
                $this->client->fetchAccessTokenWithRefreshToken($this->client->getRefreshToken());
            } else {
                // Generate new tokens
                if (isset($this->smtpSettings['gmail_auth_code']) && !empty($this->smtpSettings['gmail_auth_code'])) {
                    $tokens = $this->client->fetchAccessTokenWithAuthCode($this->smtpSettings['gmail_auth_code']);
                    $this->client->setAccessToken($tokens);
                }
            }
            $tokens = $this->client->getAccessToken();

            $smtpSettings = get_option('rtm_mail_smtp_settings');
            $smtpSettings['smtp_settings']['gmail']['gmail_access_token'] = $tokens['access_token'];
            $smtpSettings['smtp_settings']['gmail']['gmail_refresh_token'] = $tokens['refresh_token'];
            $smtpSettings['smtp_settings']['gmail']['gmail_token_expires'] = $tokens['expires_in'];
            $smtpSettings['smtp_settings']['gmail']['gmail_auth_code'] = '';
            // Save new tokens
            update_option('rtm_mail_smtp_settings', $smtpSettings);
        }
    }

    public function getAuthUrl()
    {
        if (isset($this->smtpSettings['gmail_client_id']) && !empty($this->smtpSettings['gmail_client_id']) &&
            isset($this->smtpSettings['gmail_client_secret']) && !empty($this->smtpSettings['gmail_client_secret']) &&
            isset($this->smtpSettings['gmail_redirect_uri']) && !empty($this->smtpSettings['gmail_redirect_uri'])

        ) {
            echo '<div class="notice notice-success"> ';
            echo '<p><strong>WP Mail Logger: </strong>';
            echo 'Please get the access token from <a href="' . $this->client->createAuthUrl() . '" target="_blank">HERE</a>';
            echo '</p>';
            echo '</div>';
        } else {
            echo '<div class="notice notice-error"> ';
            echo '<p><strong>WP Mail Logger: </strong>';
            echo __('Please fill in the Client ID, Client Secret key and Redirect URI and save the settings before generating auth code!', 'rtm-mail');
            echo '</p>';
            echo '</div>';
        }
    }
}
