use config::AppConfig;
use lettre::message::Mailbox;
use lettre::transport::smtp::authentication::Credentials;
use lettre::transport::smtp::client::Tls;
use lettre::{SmtpTransport, Transport};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::sync::LazyLock;
use std::time::Duration;

#[derive(Clone)]
pub struct AppEmail {
    pub cred: Credentials,
    pub mailer: SmtpTransport,
    pub from: Mailbox,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct EmailMessage {
    pub to: String,
    pub subject: String,
    pub body: String,
}

static EMAIL_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap());

impl AppEmail {
    pub async fn init(cfg: &AppConfig) -> anyhow::Result<Self> {
        let smtp_host = cfg.smtp_host()?;
        let smtp_port = cfg.smtp_port()?;
        let smtp_username = cfg.smtp_username()?;
        let smtp_password = cfg.smtp_password()?;
        let smtp_from = cfg.smtp_from()?;
        let smtp_tls = cfg.smtp_tls()?;
        let smtp_timeout = cfg.smtp_timeout()?;
        let cred = Credentials::new(smtp_username, smtp_password);
        let tls_param = if smtp_tls {
            Tls::Required(
                lettre::transport::smtp::client::TlsParameters::builder(smtp_host.clone())
                    .build()
                    .map_err(|e| anyhow::anyhow!("Failed to build TLS parameters: {}", e))?,
            )
        } else {
            Tls::None
        };

        let mailer = SmtpTransport::builder_dangerous(smtp_host)
            .port(smtp_port)
            .tls(tls_param)
            .timeout(Some(Duration::from_secs(smtp_timeout)))
            .credentials(cred.clone())
            .build();
        Ok(AppEmail {
            cred,
            mailer,
            from: smtp_from
                .parse()
                .map_err(|e| anyhow::anyhow!("Invalid from address: {}", e))?,
        })
    }
    pub async fn send(&self, msg: EmailMessage) -> anyhow::Result<()> {
        if !EMAIL_REGEX.is_match(&msg.to) {
            return Err(anyhow::anyhow!("Invalid email address format: {}", msg.to));
        }

        let email = lettre::Message::builder()
            .from(self.from.clone())
            .to(msg.to.parse()?)
            .subject(msg.subject)
            .body(msg.body)?;
        self.mailer
            .send(&email)
            .map_err(|e| anyhow::anyhow!("{}", e))?;
        Ok(())
    }
}
