//! 滥用处置：自动封禁（写黑名单，source=auto，带 TTL）。

use crate::config::abuse::AbuseConfig;
use crate::repositories::{
    abuse_repository::AbuseRepository,
    audit_repository::{AuditRepository, NewAuditLog},
    blacklist_repository::BlacklistRepository,
};
use anyhow::Result;
use sea_orm::DatabaseConnection;

pub struct AbuseService {
    blacklist: BlacklistRepository,
    abuse_repo: AbuseRepository,
    audit: AuditRepository,
    config: AbuseConfig,
}

impl AbuseService {
    pub fn new(db: DatabaseConnection, config: AbuseConfig) -> Self {
        Self {
            blacklist: BlacklistRepository::new(db.clone()),
            abuse_repo: AbuseRepository::new(db.clone()),
            audit: AuditRepository::new(db),
            config,
        }
    }

    pub async fn auto_block_sender(&self, domain: &str, reason: &str) -> Result<()> {
        if self
            .blacklist
            .find_active_sender("domain", domain)
            .await?
            .is_some()
        {
            return Ok(());
        }
        let expires = chrono::Utc::now().naive_utc()
            + chrono::Duration::seconds(self.config.auto_block_ttl_seconds);
        let model = self
            .blacklist
            .add_sender(
                "domain".into(),
                domain.into(),
                reason.into(),
                "auto".into(),
                Some(expires),
            )
            .await?;
        self.audit
            .add(NewAuditLog {
                event_type: "automatic_block".into(),
                action: "block_domain".into(),
                reason: Some(reason.into()),
                target_type: Some("blocked_sender".into()),
                target_id: Some(model.id.to_string()),
                metadata_json: Some(serde_json::json!({"domain": domain}).to_string()),
                ..Default::default()
            })
            .await?;
        tracing::warn!(domain, reason, "自动封禁发件域");
        Ok(())
    }

    pub async fn auto_block_ip(&self, ip: &str, reason: &str) -> Result<()> {
        if self.blacklist.find_active_ip(ip).await?.is_some() {
            return Ok(());
        }
        let expires = chrono::Utc::now().naive_utc()
            + chrono::Duration::seconds(self.config.auto_block_ttl_seconds);
        let model = self
            .blacklist
            .add_ip(ip.into(), reason.into(), "auto".into(), Some(expires))
            .await?;
        self.audit
            .add(NewAuditLog {
                event_type: "automatic_block".into(),
                action: "block_ip".into(),
                reason: Some(reason.into()),
                source_ip: Some(ip.into()),
                target_type: Some("blocked_ip".into()),
                target_id: Some(model.id.to_string()),
                ..Default::default()
            })
            .await?;
        tracing::warn!(ip, reason, "自动封禁 IP");
        Ok(())
    }

    #[allow(dead_code)]
    pub async fn record_event(
        &self,
        rule_id: i64,
        target: String,
        detail: Option<String>,
    ) -> Result<()> {
        self.abuse_repo.add_event(rule_id, target, detail).await
    }
}
