use crate::errors::KamError;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::PathBuf;

/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public struct 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
pub struct SecretMeta {
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'encrypted' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub encrypted: bool,
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'created_at' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub created_at: i64,
    // 存储后端："keyring"或"file"（保留字段用于向后兼容）
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'storage' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub storage: String,
    // 最后探测时间戳（毫秒，UTC）
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'last_probe' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub last_probe: i64,
    // 存储的blob大小（字节）
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'size' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub size: u64,
    // 缓存的公钥PEM（如果有的话），用于免密码操作
    #[serde(skip_serializing_if = "Option::is_none")]
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'pub_key_pem' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub pub_key_pem: Option<String>,
    // 公钥PEM的base64编码签名（用私钥签名）
    #[serde(skip_serializing_if = "Option::is_none")]
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'pub_key_signature' in 'SecretMeta'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub pub_key_signature: Option<String>,
}

impl Default for SecretMeta {
    fn default() -> Self {
        Self {
            encrypted: false,
            created_at: 0,
            storage: "file".to_string(),
            last_probe: 0,
            size: 0,
            pub_key_pem: None,
            pub_key_signature: None,
        }
    }
}

// 密钥索引，存储所有密钥的元数据
/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public struct 'SecretIndex'. Replace with real documentation. (2025-12-30T22:23:21Z)
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct SecretIndex {
    // 名字到元数据的映射
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'entries' in 'SecretIndex'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub entries: HashMap<String, SecretMeta>,
}

// 获取索引文件路径（~/.kam/secrets.json）
fn index_path() -> Result<PathBuf, KamError> {
    // Respect KAM_HOME environment variable if provided; otherwise fall back to $HOME/.kam
    let dir = crate::utils::kam_home_dir()?;
    if !dir.exists() {
        fs::create_dir_all(&dir).map_err(KamError::Io)?;
    }
    Ok(dir.join("secrets.json"))
}

/// Parse SecretMeta from JSON value with default fallbacks.
fn parse_secret_meta_from_value(val: &serde_json::Value) -> SecretMeta {
    SecretMeta {
        encrypted: val
            .get("encrypted")
            .and_then(serde_json::Value::as_bool)
            .unwrap_or(false),
        created_at: val
            .get("created_at")
            .and_then(serde_json::Value::as_i64)
            .unwrap_or(0),
        storage: val
            .get("storage")
            .and_then(serde_json::Value::as_str)
            .unwrap_or("file")
            .to_string(),
        last_probe: val
            .get("last_probe")
            .and_then(serde_json::Value::as_i64)
            .unwrap_or(0),
        size: val
            .get("size")
            .and_then(serde_json::Value::as_u64)
            .unwrap_or(0),
        pub_key_pem: val
            .get("pub_key_pem")
            .and_then(serde_json::Value::as_str)
            .map(ToString::to_string),
        pub_key_signature: val
            .get("pub_key_signature")
            .and_then(serde_json::Value::as_str)
            .map(ToString::to_string),
    }
}

/// Parse entries format: {"entries": {...}}.
fn parse_entries_format(v: &serde_json::Value) -> SecretIndex {
    let mut idx = SecretIndex::default();
    if let Some(map) = v.get("entries").and_then(|m| m.as_object()) {
        for (k, val) in map {
            idx.entries
                .insert(k.clone(), parse_secret_meta_from_value(val));
        }
    }
    idx
}

/// Parse legacy names format: {"names": [...]}.
fn parse_legacy_names_format(v: serde_json::Value) -> Result<SecretIndex, KamError> {
    #[derive(Deserialize)]
    struct Legacy {
        names: HashSet<String>,
    }
    let legacy: Legacy = serde_json::from_value(v)
        .map_err(|e| KamError::Json(format!("Failed to parse legacy secret index: {e}")))?;
    let mut idx = SecretIndex::default();
    for n in legacy.names {
        idx.entries.insert(n, SecretMeta::default());
    }
    Ok(idx)
}

/// Parse direct map format: {"name": {...}}.
fn parse_direct_map_format(v: &serde_json::Value) -> SecretIndex {
    let mut idx = SecretIndex::default();
    if let Some(obj) = v.as_object() {
        for (k, val) in obj {
            idx.entries
                .insert(k.clone(), parse_secret_meta_from_value(val));
        }
    }
    idx
}

/// Parse legacy array format: ["name1", "name2", ...].
fn parse_legacy_array_format(v: serde_json::Value) -> Result<SecretIndex, KamError> {
    let arr = serde_json::from_value::<Vec<String>>(v)
        .map_err(|e| KamError::Json(format!("Failed to parse legacy names array: {e}")))?;
    let mut idx = SecretIndex::default();
    for n in arr {
        idx.entries.insert(n, SecretMeta::default());
    }
    Ok(idx)
}

/// Normalize storage fields: default empty storage to 'file'.
fn normalize_storage_fields(idx: &mut SecretIndex) -> bool {
    let mut changed = false;
    for meta in idx.entries.values_mut() {
        if meta.storage.is_empty() {
            meta.storage = "file".to_string();
            changed = true;
        }
    }
    changed
}

/// Normalize keyring entries: check fallback files and update storage.
fn normalize_keyring_entries(idx: &mut SecretIndex) -> bool {
    let mut changed = false;
    for (name, meta) in &mut idx.entries {
        if meta.storage == "keyring" {
            let Ok(p) = super::file::secret_file_path(name) else {
                continue;
            };
            if p.exists() {
                if let Ok(metadata) = fs::metadata(&p) {
                    meta.storage = "file".to_string();
                    meta.last_probe = Utc::now().timestamp_millis();
                    meta.size = metadata.len();
                    changed = true;
                }
            } else {
                meta.storage = "unknown".to_string();
                changed = true;
            }
        }
    }
    changed
}

/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'load_index'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if the index file cannot be read or parsed (I/O errors, JSON parsing errors).
pub fn load_index() -> Result<SecretIndex, KamError> {
    let p = index_path()?;
    if !p.exists() {
        return Ok(SecretIndex::default());
    }
    let s = fs::read_to_string(&p).map_err(KamError::Io)?;
    let v: serde_json::Value = serde_json::from_str(&s)
        .map_err(|e| KamError::Json(format!("Failed to parse secret index JSON: {e}")))?;

    let mut idx = if v.get("entries").is_some() {
        parse_entries_format(&v)
    } else if v.get("names").is_some() {
        parse_legacy_names_format(v)?
    } else if v.is_object() {
        parse_direct_map_format(&v)
    } else if v.is_array() {
        parse_legacy_array_format(v)?
    } else {
        return Err(KamError::Json(
            "Unsupported secret index format".to_string(),
        ));
    };

    let mut changed = normalize_storage_fields(&mut idx);
    changed |= normalize_keyring_entries(&mut idx);

    if changed {
        save_index(&idx)?;
    }
    Ok(idx)
}

/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'save_index'. Replace with real documentation. (2025-12-30T22:23:21Z)
/// # Errors
/// Returns `KamError` on serialization or I/O failures.
pub fn save_index(idx: &SecretIndex) -> Result<(), KamError> {
    let p = index_path()?;
    let s = serde_json::to_string_pretty(idx)
        .map_err(|e| KamError::Json(format!("Failed to serialize secret index: {e}")))?;
    fs::write(&p, s).map_err(KamError::Io)?;
    Ok(())
}
