const nodemailer = require("nodemailer");
const NotificationProvider = require("./notification-provider");
const { DOWN } = require("../../src/util");
const { Liquid } = require("liquidjs");

class SMTP extends NotificationProvider {
    name = "smtp";

    /**
     * @inheritdoc
     */
    async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
        const okMsg = "Sent Successfully.";

        const config = {
            host: notification.smtpHost,
            port: notification.smtpPort,
            secure: notification.smtpSecure,
            tls: {
                rejectUnauthorized: !notification.smtpIgnoreTLSError || false,
            }
        };

        // Fix #1129
        if (notification.smtpDkimDomain) {
            config.dkim = {
                domainName: notification.smtpDkimDomain,
                keySelector: notification.smtpDkimKeySelector,
                privateKey: notification.smtpDkimPrivateKey,
                hashAlgo: notification.smtpDkimHashAlgo,
                headerFieldNames: notification.smtpDkimheaderFieldNames,
                skipFields: notification.smtpDkimskipFields,
            };
        }

        // Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
        if (notification.smtpUsername || notification.smtpPassword) {
            config.auth = {
                user: notification.smtpUsername,
                pass: notification.smtpPassword,
            };
        }

        // default values in case the user does not want to template
        let subject = msg;
        let body = msg;
        if (heartbeatJSON) {
            body = `${msg}\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`;
        }
        // subject and body are templated
        if ((monitorJSON && heartbeatJSON) || msg.endsWith("Testing")) {
            // cannot end with whitespace as this often raises spam scores
            const customSubject = notification.customSubject?.trim() || "";
            const customBody = notification.customBody?.trim() || "";

            const context = this.generateContext(msg, monitorJSON, heartbeatJSON);
            const engine = new Liquid();
            if (customSubject !== "") {
                const tpl = engine.parse(customSubject);
                subject = await engine.render(tpl, context);
            }
            if (customBody !== "") {
                const tpl = engine.parse(customBody);
                body = await engine.render(tpl, context);
            }
        }

        // send mail with defined transport object
        let transporter = nodemailer.createTransport(config);
        await transporter.sendMail({
            from: notification.smtpFrom,
            cc: notification.smtpCC,
            bcc: notification.smtpBCC,
            to: notification.smtpTo,
            subject: subject,
            text: body,
        });

        return okMsg;
    }

    /**
     * Generate context for LiquidJS
     * @param {string} msg  the message that will be included in the context
     * @param {?object} monitorJSON Monitor details (For Up/Down/Cert-Expiry only)
     * @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
     * @returns {{STATUS: string, status: string, HOSTNAME_OR_URL: string, hostnameOrUrl: string, NAME: string, name: string, monitorJSON: ?object, heartbeatJSON: ?object, msg: string}} the context
     */
    generateContext(msg, monitorJSON, heartbeatJSON) {
        // Let's start with dummy values to simplify code
        let monitorName = "Monitor Name not available";
        let monitorHostnameOrURL = "testing.hostname";

        if (monitorJSON !== null) {
            monitorName = monitorJSON["name"];

            if (monitorJSON["type"] === "http" || monitorJSON["type"] === "keyword" || monitorJSON["type"] === "json-query") {
                monitorHostnameOrURL = monitorJSON["url"];
            } else {
                monitorHostnameOrURL = monitorJSON["hostname"];
            }
        }

        let serviceStatus = "⚠️ Test";
        if (heartbeatJSON !== null) {
            serviceStatus = (heartbeatJSON["status"] === DOWN) ? "🔴 Down" : "✅ Up";
        }
        return {
            // for v1 compatibility, to be removed in v3
            "STATUS": serviceStatus,
            "NAME": monitorName,
            "HOSTNAME_OR_URL": monitorHostnameOrURL,

            // variables which are officially supported
            "status": serviceStatus,
            "name": monitorName,
            "hostnameOrURL": monitorHostnameOrURL,
            monitorJSON,
            heartbeatJSON,
            msg,
        };
    }
}

module.exports = SMTP;