//! API Key Models

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use utoipa::ToSchema;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApiKeyType {
    System,
    User,
    Service,
    Integration,
    Emergency,
}

impl ApiKeyType {
    pub fn prefix(&self) -> &'static str {
        match self {
            ApiKeyType::System => "msys_",
            ApiKeyType::User => "muser_",
            ApiKeyType::Service => "msvc_",
            ApiKeyType::Integration => "mint_",
            ApiKeyType::Emergency => "memg_",
        }
    }

    pub fn default_ttl_days(&self) -> i64 {
        match self {
            ApiKeyType::System => 365,
            ApiKeyType::User => 90,
            ApiKeyType::Service => 180,
            ApiKeyType::Integration => 30,
            ApiKeyType::Emergency => 1,
        }
    }

    pub fn grace_period_hours(&self) -> i64 {
        match self {
            ApiKeyType::System => 72,
            ApiKeyType::User => 24,
            ApiKeyType::Service => 48,
            ApiKeyType::Integration => 24,
            ApiKeyType::Emergency => 0,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ApiKeyStatus {
    Active,
    Suspended,
    Expired,
    Revoked,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RotationType {
    Scheduled,
    Manual,
    Forced,
    Emergency,
    AnomalyTriggered,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AnomalyType {
    HighRequestRate,
    HighErrorRate,
    MultipleIps,
    UnusualTime,
    BruteForce,
    DataExfiltration,
}

impl AnomalyType {
    pub fn severity(&self) -> AnomalySeverity {
        match self {
            AnomalyType::HighRequestRate => AnomalySeverity::Medium,
            AnomalyType::HighErrorRate => AnomalySeverity::Medium,
            AnomalyType::MultipleIps => AnomalySeverity::Low,
            AnomalyType::UnusualTime => AnomalySeverity::Low,
            AnomalyType::BruteForce => AnomalySeverity::Critical,
            AnomalyType::DataExfiltration => AnomalySeverity::Critical,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AnomalySeverity {
    Low,
    Medium,
    High,
    Critical,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKey {
    pub id: i64,
    pub key_id: String,
    pub key_hash: String,
    pub key_prefix: String,
    pub name: String,
    pub key_type: ApiKeyType,
    pub user_id: Option<i64>,
    pub service_name: Option<String>,
    pub permissions: HashSet<String>,
    pub expires_at: Option<DateTime<Utc>>,
    pub last_used_at: Option<DateTime<Utc>>,
    pub last_used_ip: Option<String>,
    pub usage_count: i64,
    pub status: ApiKeyStatus,
    pub rotation_required: bool,
    pub rotation_reason: Option<String>,
    pub grace_period_end: Option<DateTime<Utc>>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateApiKeyRequest {
    pub name: String,
    pub key_type: ApiKeyType,
    pub user_id: Option<i64>,
    pub service_name: Option<String>,
    pub permissions: Vec<String>,
    pub ttl_days: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateApiKeyResponse {
    pub key: String,
    pub key_id: String,
    pub expires_at: DateTime<Utc>,
    pub warning: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ValidateApiKeyRequest {
    pub key: String,
    pub ip_address: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ValidateApiKeyResponse {
    pub valid: bool,
    pub key_id: Option<String>,
    pub permissions: Option<Vec<String>>,
    pub error: Option<String>,
    pub requires_rotation: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogEntry {
    pub id: i64,
    pub key_id: String,
    pub action: String,
    pub actor: Option<String>,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub request_path: Option<String>,
    pub response_code: Option<i32>,
    pub anomaly_type: Option<AnomalyType>,
    pub details: Option<serde_json::Value>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyRecord {
    pub id: i64,
    pub key_id: String,
    pub anomaly_type: AnomalyType,
    pub severity: AnomalySeverity,
    pub ip_address: Option<String>,
    pub request_count: Option<i32>,
    pub error_count: Option<i32>,
    pub error_rate: Option<f64>,
    pub unique_ips: Option<i32>,
    pub details: Option<serde_json::Value>,
    pub resolved: bool,
    pub resolved_at: Option<DateTime<Utc>>,
    pub resolved_by: Option<String>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RotationStatus {
    pub key_id: String,
    pub requires_rotation: bool,
    pub reason: Option<String>,
    pub grace_period_end: Option<DateTime<Utc>>,
    pub in_grace_period: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyDetectionConfig {
    pub requests_per_minute_threshold: i32,
    pub requests_per_hour_threshold: i32,
    pub error_rate_threshold: f64,
    pub unique_ips_per_hour_threshold: i32,
    pub lockout_threshold: i32,
}

impl Default for AnomalyDetectionConfig {
    fn default() -> Self {
        Self {
            requests_per_minute_threshold: 1000,
            requests_per_hour_threshold: 10000,
            error_rate_threshold: 0.5,
            unique_ips_per_hour_threshold: 5,
            lockout_threshold: 3,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ApiKeyStats {
    pub total_keys: i64,
    pub active_keys: i64,
    pub expired_keys: i64,
    pub rotation_required: i64,
    pub anomalies_last_24h: i64,
}
