//! API Key Statistics Report Module
//!
//! Generates usage statistics and reports for API keys

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

/// Detailed statistics report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKeyReport {
    pub generated_at: DateTime<Utc>,
    pub period: ReportPeriod,
    pub summary: ReportSummary,
    pub by_type: Vec<TypeStats>,
    pub by_status: Vec<StatusStats>,
    pub top_usage: Vec<UsageStats>,
    pub anomalies: AnomalyStats,
}

/// Report period
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportPeriod {
    pub start: DateTime<Utc>,
    pub end: DateTime<Utc>,
    pub days: i64,
}

/// Summary statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSummary {
    pub total_keys: i64,
    pub active_keys: i64,
    pub expired_keys: i64,
    pub revoked_keys: i64,
    pub keys_needing_rotation: i64,
    pub total_usage: i64,
}

/// Statistics by key type
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeStats {
    pub key_type: String,
    pub count: i64,
    pub active: i64,
    pub expired: i64,
}

/// Statistics by status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatusStats {
    pub status: String,
    pub count: i64,
    pub percentage: f64,
}

/// Top usage statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageStats {
    pub key_id: String,
    pub name: String,
    pub usage_count: i64,
    pub last_used: Option<DateTime<Utc>>,
}

/// Anomaly statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyStats {
    pub total: i64,
    pub last_24h: i64,
    pub last_7d: i64,
    pub by_severity: Vec<SeverityStats>,
}

/// Severity statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SeverityStats {
    pub severity: String,
    pub count: i64,
}

/// Report generator
pub struct ReportGenerator {
    db: PostgresDb,
}

impl ReportGenerator {
    pub fn new(db: PostgresDb) -> Self {
        Self { db }
    }

    /// Generate a full report
    pub async fn generate_report(&self, days: i64) -> Result<ApiKeyReport> {
        let end = Utc::now();
        let start = end - Duration::days(days);

        let stats = self.db.get_api_key_stats().await?;

        Ok(ApiKeyReport {
            generated_at: Utc::now(),
            period: ReportPeriod { start, end, days },
            summary: ReportSummary {
                total_keys: stats.total_keys,
                active_keys: stats.active_keys,
                expired_keys: stats.expired_keys,
                revoked_keys: 0,
                keys_needing_rotation: stats.rotation_required,
                total_usage: 0,
            },
            by_type: vec![],
            by_status: vec![
                StatusStats {
                    status: "active".to_string(),
                    count: stats.active_keys,
                    percentage: if stats.total_keys > 0 {
                        (stats.active_keys as f64 / stats.total_keys as f64) * 100.0
                    } else {
                        0.0
                    },
                },
                StatusStats {
                    status: "expired".to_string(),
                    count: stats.expired_keys,
                    percentage: if stats.total_keys > 0 {
                        (stats.expired_keys as f64 / stats.total_keys as f64) * 100.0
                    } else {
                        0.0
                    },
                },
            ],
            top_usage: vec![],
            anomalies: AnomalyStats {
                total: 0,
                last_24h: stats.anomalies_last_24h,
                last_7d: 0,
                by_severity: vec![],
            },
        })
    }

    /// Generate text report
    pub async fn generate_text_report(&self, days: i64) -> Result<String> {
        let report = self.generate_report(days).await?;

        let mut output = String::new();
        output.push_str("=== API Key Statistics Report ===\n");
        output.push_str(&format!(
            "Generated: {}\n",
            report.generated_at.format("%Y-%m-%d %H:%M:%S")
        ));
        output.push_str(&format!(
            "Period: {} to {} ({} days)\n\n",
            report.period.start.format("%Y-%m-%d"),
            report.period.end.format("%Y-%m-%d"),
            report.period.days
        ));

        output.push_str("--- Summary ---\n");
        output.push_str(&format!(
            "Total Keys:          {}\n",
            report.summary.total_keys
        ));
        output.push_str(&format!(
            "Active Keys:         {}\n",
            report.summary.active_keys
        ));
        output.push_str(&format!(
            "Expired Keys:        {}\n",
            report.summary.expired_keys
        ));
        output.push_str(&format!(
            "Rotation Required:   {}\n\n",
            report.summary.keys_needing_rotation
        ));

        output.push_str("--- Status Distribution ---\n");
        for status in &report.by_status {
            output.push_str(&format!(
                "{:12}: {} ({:.1}%)\n",
                status.status, status.count, status.percentage
            ));
        }

        output.push_str(&format!(
            "\n--- Anomalies (Last 24h) ---\n{}\n",
            report.anomalies.last_24h
        ));

        Ok(output)
    }
}

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

    #[test]
    fn test_report_serialization() {
        let report = ApiKeyReport {
            generated_at: Utc::now(),
            period: ReportPeriod {
                start: Utc::now() - Duration::days(30),
                end: Utc::now(),
                days: 30,
            },
            summary: ReportSummary {
                total_keys: 10,
                active_keys: 8,
                expired_keys: 2,
                revoked_keys: 0,
                keys_needing_rotation: 1,
                total_usage: 1000,
            },
            by_type: vec![],
            by_status: vec![StatusStats {
                status: "active".to_string(),
                count: 8,
                percentage: 80.0,
            }],
            top_usage: vec![],
            anomalies: AnomalyStats {
                total: 5,
                last_24h: 1,
                last_7d: 3,
                by_severity: vec![],
            },
        };

        let json = serde_json::to_string_pretty(&report).unwrap();
        assert!(json.contains("\"total_keys\": 10"));
    }
}
