pub mod user_notifier;

use lettre::message::{header, Mailbox, MultiPart, SinglePart};

use lettre::transport::smtp::authentication::Credentials;
use lettre::transport::smtp::client::{Tls, TlsParameters};
use lettre::AsyncSmtpTransport;
use lettre::Message;
use lettre::Tokio1Executor;

use tera::{Context, Tera};

#[derive(Debug, Clone)]
pub struct DangerousLettre {
    mailer: AsyncSmtpTransport<Tokio1Executor>,
    from: Mailbox,
    tera: Tera,
}

impl DangerousLettre {
    pub fn new(
        host: &str,
        port: u16,
        username: &str,
        password: &str,
        from: &str,
    ) -> Result<Self, anyhow::Error> {
        let creds = Credentials::new(username.to_string(), password.to_string());

        let tls = TlsParameters::builder(host.to_owned())
            .dangerous_accept_invalid_certs(true)
            .dangerous_accept_invalid_hostnames(true)
            .build()?;

        let mailer: AsyncSmtpTransport<Tokio1Executor> =
            AsyncSmtpTransport::<Tokio1Executor>::builder_dangerous(host)
                .port(port)
                .tls(Tls::Opportunistic(tls))
                .credentials(creds)
                .build();

        let tera = Tera::new("templates/**/*.email.*")?;

        let from = from.parse::<Mailbox>()?;

        Ok(Self { mailer, from, tera })
    }

    pub fn template(
        &self,
        template: &str,
        subject: &str,
        context: &Context,
        to: Mailbox,
    ) -> Result<Message, anyhow::Error> {
        let plain_text = self
            .tera
            .render(&format!("{}.email.txt", template), context)?;

        let html = self
            .tera
            .render(&format!("{}.email.html", template), context)?;

        let message = Message::builder()
            .subject(subject)
            .from(self.from.clone())
            .to(to)
            .multipart(
                MultiPart::alternative() // This is composed of two parts.
                    .singlepart(
                        SinglePart::builder()
                            .header(header::ContentType::TEXT_PLAIN)
                            .body(plain_text), // Every message should have a plain text fallback.
                    )
                    .singlepart(
                        SinglePart::builder()
                            .header(header::ContentType::TEXT_HTML)
                            .body(html),
                    ),
            )?;

        Ok(message)
    }
}
