//! 环境变量解析模块
//!
//! 提供配置文件中环境变量占位符的解析功能
//! 支持 Shell 风格的语法：${VAR}、$VAR、${VAR:-default} 等

use std::borrow::Cow;

/// 解析字符串中的环境变量占位符
///
/// 支持的语法：
/// - `${VAR_NAME}`          - 标准格式（推荐）
/// - `$VAR_NAME`            - 简写格式
/// - `${VAR_NAME:-default}` - 带默认值（bash 标准语法）
///
/// # 参数
/// - `text`: 待解析的字符串
///
/// # 返回值
/// - `String`: 替换后的字符串
/// - `bool`: 是否检测到并替换了环境变量
pub fn expand_env_vars(text: &str) -> (String, bool) {
    // 使用 shellexpand::env() 解析环境变量
    // 该函数仅处理环境变量，不处理 tilde (~) 扩展，适合配置文件场景
    match shellexpand::env(text) {
        Ok(expanded) => {
            // 通过比较原始字符串和扩展后的字符串判断是否发生了替换
            let changed = match &expanded {
                Cow::Borrowed(_) => false, // 未发生变化，仍是借用
                Cow::Owned(_) => true,     // 发生了变化，产生了新字符串
            };

            (expanded.into_owned(), changed)
        }
        Err(e) => {
            // 如果解析失败（例如变量引用语法错误），记录警告并返回原字符串
            tracing::warn!("Failed to expand environment variables in config: {}", e);
            (text.to_string(), false)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{remove_env_var, set_env_var};

    #[test]
    fn test_expand_standard_syntax() {
        set_env_var("TEST_VAR_STANDARD", "test_value");
        let (result, changed) = expand_env_vars("secret=${TEST_VAR_STANDARD}");
        assert_eq!(result, "secret=test_value");
        assert!(changed);
    }

    #[test]
    fn test_expand_short_syntax() {
        set_env_var("TEST_VAR_SHORT", "short_value");
        let (result, changed) = expand_env_vars("key=$TEST_VAR_SHORT");
        assert_eq!(result, "key=short_value");
        assert!(changed);
    }

    #[test]
    fn test_expand_with_default() {
        // 确保变量未定义
        remove_env_var("UNDEFINED_VAR_WITH_DEFAULT");
        let (result, changed) = expand_env_vars("port=${UNDEFINED_VAR_WITH_DEFAULT:-8080}");
        assert_eq!(result, "port=8080");
        assert!(changed);
    }

    #[test]
    fn test_no_env_vars() {
        let (result, changed) = expand_env_vars("plain text without variables");
        assert_eq!(result, "plain text without variables");
        assert!(!changed);
    }

    #[test]
    fn test_empty_string() {
        let (result, changed) = expand_env_vars("");
        assert_eq!(result, "");
        assert!(!changed);
    }

    #[test]
    fn test_multiple_vars() {
        set_env_var("VAR1", "value1");
        set_env_var("VAR2", "value2");
        let (result, changed) = expand_env_vars("${VAR1} and ${VAR2}");
        assert_eq!(result, "value1 and value2");
        assert!(changed);
    }

    #[test]
    fn test_undefined_var_without_default() {
        // 确保变量未定义
        remove_env_var("COMPLETELY_UNDEFINED_VAR");
        let (result, changed) = expand_env_vars("value=${COMPLETELY_UNDEFINED_VAR}");
        // shellexpand::env 对未定义的变量会保持原样
        assert_eq!(result, "value=${COMPLETELY_UNDEFINED_VAR}");
        assert!(!changed);
    }

    #[test]
    fn test_complex_toml_config() {
        set_env_var("ET_SECRET", "my-secret-key");
        set_env_var("ET_PORT", "11010");

        let config = r#"
[network_identity]
network_name = "test-network"
network_secret = "${ET_SECRET}"

[[peer]]
uri = "tcp://127.0.0.1:${ET_PORT}"
"#;

        let (result, changed) = expand_env_vars(config);
        assert!(changed);
        assert!(result.contains(r#"network_secret = "my-secret-key""#));
        assert!(result.contains(r#"uri = "tcp://127.0.0.1:11010""#));
    }

    #[test]
    fn test_escape_syntax_double_dollar() {
        set_env_var("ESCAPED_VAR", "should_not_expand");
        // shellexpand 使用 $$ 作为转义序列，表示字面量的单个 $
        // $$ 会被转义为单个 $，不会触发变量扩展
        let (result, changed) = expand_env_vars("value=$${ESCAPED_VAR}");
        assert_eq!(result, "value=${ESCAPED_VAR}");
        assert!(changed); // $$ -> $ 被视为一次变换
    }

    #[test]
    fn test_escape_syntax_backslash() {
        set_env_var("ESCAPED_VAR", "should_not_expand");
        // shellexpand 中反斜杠转义的行为：\$ 会展开为 \<变量值>
        // 这不是推荐的转义方式，此测试仅为记录实际行为
        let (result, changed) = expand_env_vars(r"value=\${ESCAPED_VAR}");
        assert_eq!(result, r"value=\should_not_expand");
        assert!(changed);
    }

    #[test]
    fn test_multiple_dollar_signs() {
        set_env_var("TEST_VAR", "value");
        // 测试多个连续的 $ 符号
        let (result1, changed1) = expand_env_vars("$$");
        assert_eq!(result1, "$");
        assert!(changed1);

        let (result2, changed2) = expand_env_vars("$$$$");
        assert_eq!(result2, "$$");
        assert!(changed2);

        // $$ 后跟变量扩展
        let (result3, changed3) = expand_env_vars("$$$TEST_VAR");
        assert_eq!(result3, "$value");
        assert!(changed3);
    }

    #[test]
    fn test_empty_var_value() {
        set_env_var("EMPTY_VAR", "");
        let (result, changed) = expand_env_vars("value=${EMPTY_VAR}");
        // 变量存在但值为空
        assert_eq!(result, "value=");
        assert!(changed);
    }

    #[test]
    fn test_default_with_special_chars() {
        remove_env_var("UNDEFINED_SPECIAL");
        // 测试默认值包含冒号、等号、空格等特殊字符
        let (result, changed) = expand_env_vars("url=${UNDEFINED_SPECIAL:-http://localhost:8080}");
        assert_eq!(result, "url=http://localhost:8080");
        assert!(changed);

        let (result2, changed2) = expand_env_vars("key=${UNDEFINED_SPECIAL:-name=value}");
        assert_eq!(result2, "key=name=value");
        assert!(changed2);

        let (result3, changed3) = expand_env_vars("msg=${UNDEFINED_SPECIAL:-hello world}");
        assert_eq!(result3, "msg=hello world");
        assert!(changed3);
    }

    #[test]
    fn test_var_name_with_numbers_underscores() {
        set_env_var("VAR_123", "num_value");
        set_env_var("_VAR", "underscore_prefix");
        set_env_var("VAR_", "underscore_suffix");

        let (result1, changed1) = expand_env_vars("${VAR_123}");
        assert_eq!(result1, "num_value");
        assert!(changed1);

        let (result2, changed2) = expand_env_vars("${_VAR}");
        assert_eq!(result2, "underscore_prefix");
        assert!(changed2);

        let (result3, changed3) = expand_env_vars("${VAR_}");
        assert_eq!(result3, "underscore_suffix");
        assert!(changed3);
    }

    #[test]
    fn test_invalid_syntax() {
        // 测试无效语法的处理
        let (result1, changed1) = expand_env_vars("${}");
        // shellexpand 会保留无效语法原样
        assert_eq!(result1, "${}");
        assert!(!changed1);

        // 注意：未闭合的 ${VAR 实际上 shellexpand 会当作普通文本处理
        // 它会尝试查找名为 "VAR" 的环境变量（到字符串末尾）
        remove_env_var("VAR");
        let (result2, _changed2) = expand_env_vars("incomplete ${VAR");
        // 如果 VAR 未定义，shellexpand 会返回错误或保持原样
        assert_eq!(result2, "incomplete ${VAR");
        // 注意：changed2 的值取决于 shellexpand 是否认为这是有效语法
        // 因此不对 changed2 做断言
    }

    #[test]
    fn test_mixed_defined_undefined_vars() {
        set_env_var("DEFINED_VAR", "defined");
        remove_env_var("UNDEFINED_VAR");

        // 混合已定义和未定义的变量
        // shellexpand::env 在遇到未定义变量时会返回错误（默认行为）
        // 因此整个字符串会保持不变
        let (result, changed) = expand_env_vars("${DEFINED_VAR} and ${UNDEFINED_VAR}");
        assert_eq!(result, "${DEFINED_VAR} and ${UNDEFINED_VAR}");
        assert!(!changed);
    }

    #[test]
    fn test_nested_braces() {
        set_env_var("OUTER", "outer_value");
        // 嵌套的大括号是无效语法，shellexpand::env 会返回错误
        let (result, changed) = expand_env_vars("${OUTER} and ${{INNER}}");
        // 由于语法错误，整个字符串保持不变
        assert_eq!(result, "${OUTER} and ${{INNER}}");
        assert!(!changed);
    }
}
