//! Configuration properties.

use parking_lot::RwLock;
use serde_json::Value;
use std::collections::HashMap;
use std::path::PathBuf;

lazy_static::lazy_static! {
    /// Global properties store.
    static ref PROPS: RwLock<HashMap<String, Value>> = RwLock::new(HashMap::new());

    /// Cached robot info.
    static ref ROBOT_INFO: RwLock<Option<HashMap<String, Value>>> = RwLock::new(None);
}

/// Load properties from the config file.
pub fn load_props() {
    let config_path = get_config_path();
    if let Ok(content) = std::fs::read_to_string(&config_path) {
        // Parse Java properties format
        for line in content.lines() {
            let line = line.trim();
            if line.is_empty() || line.starts_with('#') {
                continue;
            }
            if let Some(idx) = line.find('=') {
                let key = line[..idx].trim().to_string();
                let value = line[idx + 1..].trim().to_string();
                PROPS.write().insert(key, Value::String(value));
            }
        }
    }
}

/// Get a string property.
pub fn get_string(key: &str, default: &str) -> String {
    PROPS
        .read()
        .get(key)
        .and_then(|v| v.as_str())
        .map(|s| s.to_string())
        .unwrap_or_else(|| default.to_string())
}

/// Get a boolean property.
pub fn get_bool(key: &str, default: bool) -> bool {
    PROPS
        .read()
        .get(key)
        .and_then(|v| {
            if let Some(b) = v.as_bool() {
                Some(b)
            } else if let Some(s) = v.as_str() {
                s.parse().ok()
            } else {
                None
            }
        })
        .unwrap_or(default)
}

/// Get an integer property.
pub fn get_int(key: &str, default: i64) -> i64 {
    PROPS
        .read()
        .get(key)
        .and_then(|v| {
            if let Some(n) = v.as_i64() {
                Some(n)
            } else if let Some(s) = v.as_str() {
                s.parse().ok()
            } else {
                None
            }
        })
        .unwrap_or(default)
}

/// Get the config file path.
fn get_config_path() -> PathBuf {
    let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
    home.join(".config")
        .join("robomotion")
        .join("config.properties")
}

/// Get robot info from cache or client (cached version).
pub async fn get_robot_info_cached() -> crate::runtime::Result<HashMap<String, Value>> {
    {
        let cached = ROBOT_INFO.read();
        if let Some(info) = cached.as_ref() {
            return Ok(info.clone());
        }
    }

    let info = crate::runtime::client::get_robot_info_internal().await?;
    *ROBOT_INFO.write() = Some(info.clone());
    Ok(info)
}

/// Get the robot version.
pub async fn get_robot_version() -> crate::runtime::Result<String> {
    let info = get_robot_info_cached().await?;
    Ok(info
        .get("version")
        .and_then(|v| v.as_str())
        .unwrap_or("0.0.0")
        .to_string())
}

/// Get the robot ID (cached version).
pub async fn get_robot_id_cached() -> crate::runtime::Result<String> {
    let info = get_robot_info_cached().await?;
    Ok(info
        .get("id")
        .and_then(|v| v.as_str())
        .unwrap_or("unknown")
        .to_string())
}
