//! API Key Export/Import Module
//!
//! Supports exporting and importing API key records

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

/// Export format
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExportFormat {
    Json,
    Csv,
}

impl ExportFormat {
    pub fn extension(&self) -> &'static str {
        match self {
            ExportFormat::Json => "json",
            ExportFormat::Csv => "csv",
        }
    }
}

/// Exported API key record (without sensitive data)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportedApiKey {
    pub key_id: String,
    pub name: String,
    pub key_type: String,
    pub status: String,
    pub permissions: serde_json::Value,
    pub expires_at: Option<DateTime<Utc>>,
    pub usage_count: i64,
    pub created_at: DateTime<Utc>,
    pub rotation_required: bool,
}

/// Export container
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportContainer {
    pub exported_at: DateTime<Utc>,
    pub version: String,
    pub count: usize,
    pub keys: Vec<ExportedApiKey>,
}

/// Import result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportResult {
    pub imported: u32,
    pub skipped: u32,
    pub errors: Vec<String>,
}

/// Export manager
pub struct ExportManager {
    db: PostgresDb,
}

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

    /// Export all API keys
    pub async fn export_all(&self, format: ExportFormat) -> Result<String> {
        let keys = self.db.list_api_keys().await?;

        let exported: Vec<ExportedApiKey> = keys
            .into_iter()
            .map(|k| ExportedApiKey {
                key_id: k.key_id,
                name: k.name,
                key_type: k.key_type,
                status: k.status,
                permissions: k.permissions,
                expires_at: k.expires_at,
                usage_count: k.usage_count,
                created_at: k.created_at,
                rotation_required: k.rotation_required,
            })
            .collect();

        let container = ExportContainer {
            exported_at: Utc::now(),
            version: "1.0".to_string(),
            count: exported.len(),
            keys: exported,
        };

        match format {
            ExportFormat::Json => Ok(serde_json::to_string_pretty(&container)?),
            ExportFormat::Csv => self.to_csv(&container),
        }
    }

    /// Export to file
    pub async fn export_to_file(&self, path: &Path, format: ExportFormat) -> Result<usize> {
        let content = self.export_all(format).await?;
        let count = serde_json::from_str::<ExportContainer>(&content)
            .map(|c| c.count)
            .unwrap_or(0);

        tokio::fs::write(path, content).await?;
        Ok(count)
    }

    /// Convert to CSV
    fn to_csv(&self, container: &ExportContainer) -> Result<String> {
        let mut csv = String::new();
        csv.push_str("key_id,name,key_type,status,usage_count,created_at,rotation_required\n");

        for key in &container.keys {
            csv.push_str(&format!(
                "{},{},{},{},{},{},{}\n",
                key.key_id,
                key.name,
                key.key_type,
                key.status,
                key.usage_count,
                key.created_at.format("%Y-%m-%d %H:%M:%S"),
                key.rotation_required,
            ));
        }

        Ok(csv)
    }
}

/// Import manager
pub struct ImportManager {
    db: PostgresDb,
}

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

    /// Import from JSON string
    pub async fn import_from_json(&self, json: &str, overwrite: bool) -> Result<ImportResult> {
        let container: ExportContainer = serde_json::from_str(json)?;
        let mut result = ImportResult {
            imported: 0,
            skipped: 0,
            errors: vec![],
        };

        for key in container.keys {
            match self.import_key(&key, overwrite).await {
                Ok(true) => result.imported += 1,
                Ok(false) => result.skipped += 1,
                Err(e) => {
                    result.errors.push(format!("{}: {}", key.key_id, e));
                }
            }
        }

        Ok(result)
    }

    /// Import from file
    pub async fn import_from_file(&self, path: &Path, overwrite: bool) -> Result<ImportResult> {
        let content = tokio::fs::read_to_string(path).await?;

        if path.extension().map(|e| e == "json").unwrap_or(false) {
            self.import_from_json(&content, overwrite).await
        } else {
            anyhow::bail!("Unsupported file format")
        }
    }

    /// Import a single key
    async fn import_key(&self, key: &ExportedApiKey, overwrite: bool) -> Result<bool> {
        // Check if key already exists
        let existing = self.db.get_api_key_by_key_id(&key.key_id).await?;

        if existing.is_some() && !overwrite {
            return Ok(false);
        }

        // Note: Import only creates metadata, not the actual key hash
        // The actual key needs to be regenerated
        tracing::info!("Imported key metadata: {} ({})", key.key_id, key.name);

        Ok(true)
    }
}

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

    #[test]
    fn test_export_format_extension() {
        assert_eq!(ExportFormat::Json.extension(), "json");
        assert_eq!(ExportFormat::Csv.extension(), "csv");
    }

    #[test]
    fn test_export_container_serialization() {
        let container = ExportContainer {
            exported_at: Utc::now(),
            version: "1.0".to_string(),
            count: 1,
            keys: vec![ExportedApiKey {
                key_id: "test_123".to_string(),
                name: "test".to_string(),
                key_type: "service".to_string(),
                status: "active".to_string(),
                permissions: serde_json::json!(["read"]),
                expires_at: None,
                usage_count: 0,
                created_at: Utc::now(),
                rotation_required: false,
            }],
        };

        let json = serde_json::to_string_pretty(&container).unwrap();
        assert!(json.contains("\"key_id\": \"test_123\""));
    }
}
