use config::AppConfig;
use queue::{AckAction, MessageHandler, NatsConsumer};
use tracing::error;

use crate::{EmailMessage, SmtpEmailSender};

pub struct EmailWorker {
    sender: SmtpEmailSender,
}

impl EmailWorker {
    pub fn new(sender: SmtpEmailSender) -> Self {
        Self { sender }
    }

    pub async fn start(config: &AppConfig) -> anyhow::Result<()> {
        let worker = Self::new(SmtpEmailSender::new(config)?);
        let consumer =
            NatsConsumer::new(config, &config.email_consumer_group_id())
                .await?;
        let topic = config.email_topic();
        consumer.start_consuming(&[topic.as_str()], worker).await?;
        std::future::pending().await
    }
}

#[async_trait::async_trait]
impl MessageHandler for EmailWorker {
    async fn handle(&self, topic: &str, payload: &[u8]) -> AckAction {
        let message = match serde_json::from_slice::<EmailMessage>(payload) {
            Ok(message) => message,
            Err(error) => {
                error!(topic, error = %error, "invalid email message payload");
                return AckAction::Ack;
            }
        };

        match self.sender.send(message).await {
            Ok(()) => AckAction::Ack,
            Err(error) => {
                error!(topic, error = %error, "email message send failed");
                AckAction::Nack
            }
        }
    }
}
