use std::mem::ManuallyDrop;

use mail_send::{Result, SmtpClient, SmtpClientBuilder, smtp::message::IntoMessage};
use tokio::net::TcpStream;
use tokio_rustls::client::TlsStream;

use crate::Signer;

pub struct Smtp<'a> {
  client: ManuallyDrop<SmtpClient<TlsStream<TcpStream>>>,
  signer: &'a Signer,
}

impl<'a> Smtp<'a> {
  pub async fn connect(server: &str, signer: &'a Signer) -> Result<Self> {
    Ok(Self {
      signer,
      client: ManuallyDrop::new(
        SmtpClientBuilder::new(server, 25)
          .implicit_tls(false)
          .timeout(std::time::Duration::from_secs(10))
          .connect()
          .await?,
      ),
    })
  }

  pub async fn send(&mut self, mail: impl IntoMessage<'_>) -> Result<()> {
    self.client.send_signed(mail, self.signer).await
  }

  // 重置连接状态 / Reset connection state
  pub async fn rset(&mut self) -> Result<()> {
    self.client.rset().await
  }
}

impl Drop for Smtp<'_> {
  fn drop(&mut self) {
    // SAFETY: drop 只会被调用一次 / drop is only called once
    let client = unsafe { ManuallyDrop::take(&mut self.client) };
    tokio::spawn(async move {
      let _ = client.quit().await;
    });
  }
}
