//! 灰名单 Greylisting：首次见 → Defer(450)，过 retry_delay 重试 → Pass。
//! 主存 Redis（triplet -> first_seen）；Redis 不可用或未启用则放行。

use crate::config::smtp::SmtpConfig;
use crate::infra::redis::redis_client::RedisClient;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GreyResult {
    Pass,
    Defer,
}

pub struct GreylistService {
    redis: Option<RedisClient>,
    config: SmtpConfig,
}

impl GreylistService {
    pub fn new(redis: Option<RedisClient>, config: SmtpConfig) -> Self {
        Self { redis, config }
    }

    pub async fn evaluate(&self, ip: &str, mail_from: &str, rcpt: &str) -> GreyResult {
        if !self.config.greylist_enabled {
            return GreyResult::Pass;
        }
        let redis = match &self.redis {
            Some(r) => r,
            None => return GreyResult::Pass, // Redis 不可用：放行（fail-open）
        };
        let key = format!("greylist:{ip}|{mail_from}|{rcpt}");
        let first_seen = redis.get(&key).await.ok().flatten();
        match first_seen {
            None => {
                let now = chrono::Utc::now().timestamp();
                let _ = redis
                    .set_ex(
                        &key,
                        &now.to_string(),
                        self.config.greylist_entry_ttl_seconds as u64,
                    )
                    .await;
                GreyResult::Defer
            }
            Some(ts) => {
                let first: i64 = ts.parse().unwrap_or(0);
                let elapsed = chrono::Utc::now().timestamp() - first;
                if elapsed >= self.config.greylist_retry_delay_seconds {
                    GreyResult::Pass
                } else {
                    GreyResult::Defer
                }
            }
        }
    }
}
