//! API Key Cleanup Module
//!
//! Automatically cleans up expired and old API key records

use crate::core::db::PostgresDb;
use anyhow::Result;
use chrono::{Duration, Utc};
use serde::{Deserialize, Serialize};

/// Cleanup configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupConfig {
    pub expired_keys_days: i64,
    pub audit_logs_days: i64,
    pub anomaly_logs_days: i64,
    pub dry_run: bool,
}

impl Default for CleanupConfig {
    fn default() -> Self {
        Self {
            expired_keys_days: std::env::var("CLEANUP_EXPIRED_KEYS_DAYS")
                .unwrap_or_else(|_| "90".to_string())
                .parse()
                .unwrap_or(90),
            audit_logs_days: std::env::var("CLEANUP_AUDIT_LOGS_DAYS")
                .unwrap_or_else(|_| "180".to_string())
                .parse()
                .unwrap_or(180),
            anomaly_logs_days: std::env::var("CLEANUP_ANOMALY_LOGS_DAYS")
                .unwrap_or_else(|_| "90".to_string())
                .parse()
                .unwrap_or(90),
            dry_run: false,
        }
    }
}

/// Cleanup result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupResult {
    pub executed_at: chrono::DateTime<Utc>,
    pub expired_keys_deleted: u64,
    pub audit_logs_deleted: u64,
    pub anomaly_logs_deleted: u64,
    pub dry_run: bool,
}

/// Cleanup manager
pub struct CleanupManager {
    db: PostgresDb,
    config: CleanupConfig,
}

impl CleanupManager {
    pub fn new(db: PostgresDb, config: CleanupConfig) -> Self {
        Self { db, config }
    }

    pub fn with_default_config(db: PostgresDb) -> Self {
        Self::new(db, CleanupConfig::default())
    }

    /// Run full cleanup
    pub async fn run_cleanup(&self) -> Result<CleanupResult> {
        let mut result = CleanupResult {
            executed_at: Utc::now(),
            expired_keys_deleted: 0,
            audit_logs_deleted: 0,
            anomaly_logs_deleted: 0,
            dry_run: self.config.dry_run,
        };

        // Clean expired keys
        result.expired_keys_deleted = self.clean_expired_keys().await?;

        // Clean old audit logs
        result.audit_logs_deleted = self.clean_audit_logs().await?;

        // Clean old anomaly logs
        result.anomaly_logs_deleted = self.clean_anomaly_logs().await?;

        tracing::info!(
            "Cleanup completed: {} expired keys, {} audit logs, {} anomaly logs",
            result.expired_keys_deleted,
            result.audit_logs_deleted,
            result.anomaly_logs_deleted
        );

        Ok(result)
    }

    /// Clean expired API keys
    async fn clean_expired_keys(&self) -> Result<u64> {
        let cutoff = Utc::now() - Duration::days(self.config.expired_keys_days);

        if self.config.dry_run {
            let count: i64 = sqlx::query_scalar(
                "SELECT COUNT(*) FROM api_keys WHERE status = 'expired' AND expires_at < $1",
            )
            .bind(cutoff)
            .fetch_one(self.db.pool())
            .await?;
            return Ok(count as u64);
        }

        let result =
            sqlx::query("DELETE FROM api_keys WHERE status = 'expired' AND expires_at < $1")
                .bind(cutoff)
                .execute(self.db.pool())
                .await?;

        Ok(result.rows_affected())
    }

    /// Clean old audit logs
    async fn clean_audit_logs(&self) -> Result<u64> {
        let cutoff = Utc::now() - Duration::days(self.config.audit_logs_days);

        if self.config.dry_run {
            let count: i64 =
                sqlx::query_scalar("SELECT COUNT(*) FROM api_key_audit_log WHERE created_at < $1")
                    .bind(cutoff)
                    .fetch_one(self.db.pool())
                    .await?;
            return Ok(count as u64);
        }

        let result = sqlx::query("DELETE FROM api_key_audit_log WHERE created_at < $1")
            .bind(cutoff)
            .execute(self.db.pool())
            .await?;

        Ok(result.rows_affected())
    }

    /// Clean old anomaly logs
    async fn clean_anomaly_logs(&self) -> Result<u64> {
        let cutoff = Utc::now() - Duration::days(self.config.anomaly_logs_days);

        if self.config.dry_run {
            let count: i64 = sqlx::query_scalar(
                "SELECT COUNT(*) FROM api_key_anomalies WHERE created_at < $1 AND resolved = TRUE",
            )
            .bind(cutoff)
            .fetch_one(self.db.pool())
            .await?;
            return Ok(count as u64);
        }

        let result =
            sqlx::query("DELETE FROM api_key_anomalies WHERE created_at < $1 AND resolved = TRUE")
                .bind(cutoff)
                .execute(self.db.pool())
                .await?;

        Ok(result.rows_affected())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_cleanup_config_default() {
        let config = CleanupConfig::default();
        assert!(config.expired_keys_days > 0);
        assert!(config.audit_logs_days > 0);
        assert!(config.anomaly_logs_days > 0);
    }
}
