// eslint-disable-next-line max-classes-per-file
import fs from 'fs';
import nodemailer from 'nodemailer';
import IMailService, { Mail } from '../declarations/mailServiceInterface';
import { NotificationResponse } from '../declarations/notificationServiceInterface';
import EnvVariableHelper from '../utils/envVariableHelper';
import Logger from '../utils/logger';

type MailServerSettings = {
    smtpHost: string;
    smtpPort: number;
    smtpFromName: string;
    smtpFromAddress: string;
    smtpEncrypted: boolean;
    dkim?: {
        domainName: string;
        keySelector: string;
        privateKey: string;
    };
    smtpAuth: {
        user: string;
        pass: string;
    };
};

export function getDkimSettings() {
    const domainName =
        EnvVariableHelper.VARIABLES.MAIL_SMTP_OPTIONAL_DKIM_DOMAIN_NAME;
    const keySelector =
        EnvVariableHelper.VARIABLES.MAIL_SMTP_OPTIONAL_DKIM_KEY_SELECTOR;
    const privateKeyFile =
        EnvVariableHelper.VARIABLES.MAIL_SMTP_OPTIONAL_DKIM_CERT_FILE;

    if (!domainName || !keySelector || !privateKeyFile) {
        return undefined;
    }

    let privateKey;

    try {
        privateKey = fs.readFileSync(privateKeyFile, 'utf-8');
    } catch (e: any) {
        if (e.code === 'ENOENT') {
            Logger.sendMessage(
                `File ${privateKeyFile} with private key not found`
            );
        }

        return undefined;
    }

    return {
        domainName,
        keySelector,
        privateKey,
    };
}

const nodemailerMailServiceSettings: MailServerSettings = {
    smtpHost: EnvVariableHelper.VARIABLES.MAIL_SMTP_HOST,
    smtpPort: EnvVariableHelper.VARIABLES.MAIL_SMTP_PORT,
    smtpFromName: 'CineShare Notifier',
    smtpFromAddress: EnvVariableHelper.VARIABLES.MAIL_SMTP_FROM_ADDRESS,
    smtpEncrypted: EnvVariableHelper.VARIABLES.MAIL_SMTP_ENCRYPTED,
    dkim: getDkimSettings(),
    smtpAuth: {
        user: EnvVariableHelper.VARIABLES.MAIL_SMTP_AUTH_USER,
        pass: EnvVariableHelper.VARIABLES.MAIL_SMTP_AUTH_PASSWORD,
    },
};

export class NodemailerMailService implements IMailService {
    private transporter: nodemailer.Transporter;

    constructor(
        // eslint-disable-next-line no-unused-vars
        private settings: MailServerSettings = nodemailerMailServiceSettings
    ) {
        this.transporter = nodemailer.createTransport({
            host: this.settings.smtpHost,
            port: this.settings.smtpPort,
            secure: this.settings.smtpEncrypted, // true for 465, false for other ports
            dkim: this.settings.dkim,
            auth: {
                user: this.settings.smtpAuth.user,
                pass: this.settings.smtpAuth.pass,
            },
        });
    }

    async sendMail(mail: Mail): Promise<NotificationResponse> {
        const msg = {
            from: {
                name: this.settings.smtpFromName,
                address: this.settings.smtpFromAddress,
            },
            to: mail.to,
            subject: mail.subject,
            text: mail.text,
            html: mail.html,
        };

        const response = await this.transporter.sendMail(msg);

        return {
            statusCode: 250,
            headers: {
                messageId: response.messageId,
                envelope: response.envelope,
                response: response.response,
            },
        };
    }
}

export const nodemailerMailService = new NodemailerMailService(
    nodemailerMailServiceSettings
);
