//! 条件表达式引擎 — 用于 DAG 边上的条件判断
//!
//! 支持的语法(由低到高优先级):
//!
//! - 逻辑或 `or`
//! - 逻辑与 `and`
//! - 逻辑非 `not`(一元前缀)
//! - 括号分组 `( ... )`
//! - 比较 `==` `!=` `>` `>=` `<` `<=` `contains`
//! - 操作数:
//!   - 布尔字面量 `true` / `false`
//!   - 单引号字符串 `'completed'`(内部 `''` 转义为单引号)
//!   - 数字字面量 `10` / `-3.5`(支持负数、小数)
//!   - JSON Path `$.a.b` / `$.list[0]` / `$['key with space']`(从求值 context 取值)
//!
//! 安全约束:
//! - **求值失败保守 false** —— 任何解析错误、JSON Path 找不到、类型不兼容,均返回 `Ok(false)`
//!   而非 `Err`。条件分支写错或 context 缺字段时不应静默放行(默认 false = 保守拒绝)。
//!   `evaluate` 实现把所有错误路径(tokenize 失败、parse 失败)都吞成 `Ok(false)`,
//!   永不返回 `Err`;`anyhow::Result<bool>` 签名仅作为未来扩展点保留(若日后需向调用方
//!   区分「表达式非法」与「求值结果为 false」,可在此放开)。当前 executor 无需处理 `Err`。
//! - `contains`:左值为字符串 → 子串匹配;左值为数组 → 元素存在性匹配;其余类型 → false。
//! - `>` `<` `>=` `<=`:仅两端正数/负数/小数(数值)才比较;任一非数值 → false。
//!
//! 实现说明:手写递归下降解析器,无第三方依赖(jsonpath crate 引入会拉额外体积,
//! 且当前需求仅需点路径 + 下标,手写更可控)。表达式按需惰性求值,短路 and/or。

use serde_json::Value;

/// 条件表达式求值器
pub struct ConditionEngine;

impl ConditionEngine {
    /// 求值条件表达式
    ///
    /// 详见模块级文档的语法与安全约束。**求值失败保守 false**:解析错误、JSON Path 缺失、
    /// 类型不兼容一律返回 `Ok(false)`,不静默放行(默认 false = 保守拒绝)。
    pub fn evaluate(expr: &str, context: &Value) -> anyhow::Result<bool> {
        let trimmed = expr.trim();
        if trimmed.is_empty() {
            // 空表达式:保守 false。配置漏写条件时留可观测线索(非用户笔误,但利于排查
            // 「为什么这条边条件总不满足」——可能是上游未填 condition 字段)。
            tracing::warn!(
                target: "df_workflow::conditions",
                "条件表达式为空,求值保守 false(检查 edge.condition 是否漏填)"
            );
            return Ok(false);
        }

        let toks = match tokenize(trimmed) {
            Ok(t) => t,
            // tokenizer 阶段即非法(如未闭合引号、单 = 、未识别关键字):保守 false,不静默放行。
            // 留 warn 记录表达式片段,排查笔误(如 status 拼错、引号未闭合)有据可循。
            // 表达式可能较长,仅取前 200 字符防日志膨胀。
            Err(_) => {
                let preview = if trimmed.len() > 200 {
                    format!("{}...(截断)", &trimmed[..trimmed.floor_char_boundary(200)])
                } else {
                    trimmed.to_string()
                };
                tracing::warn!(
                    target: "df_workflow::conditions",
                    expr = %preview,
                    "条件表达式 tokenize 失败(疑似未闭合引号/非法符号/未识别关键字),求值保守 false"
                );
                return Ok(false);
            }
        };
        let mut parser = Parser { toks, pos: 0, ctx: context };

        match parser.parse_or() {
            Ok(v) => Ok(v),
            // 解析错误保守 false:与历史行为「未识别表达式默认 false」一致,不破坏调用方。
            // 留 warn 记录表达式片段,排查结构错误(如括号不闭合、操作数缺失)有据可循。
            Err(_) => {
                let preview = if trimmed.len() > 200 {
                    format!("{}...(截断)", &trimmed[..trimmed.floor_char_boundary(200)])
                } else {
                    trimmed.to_string()
                };
                tracing::warn!(
                    target: "df_workflow::conditions",
                    expr = %preview,
                    "条件表达式解析失败(疑似括号不闭合/操作数缺失/结构错误),求值保守 false"
                );
                Ok(false)
            }
        }
    }
}

// ============================================================================
// JSON Path 求值 —— 手写,支持点路径 / 下标 / 单引号键
// ============================================================================

/// 按手写 JSON Path 从 context 取值。
///
/// 支持语法:
/// - `$.a.b`     点取字段
/// - `$.a[0]`    数组下标(支持负数从尾部,-1 = 末尾)
/// - `$['a b']`  单引号键(支持含空格/特殊字符的键名)
///
/// `path` 必须以 `$` 起头;解析失败或路径不存在返回 `None`(调用方据此保守 false)。
fn eval_jsonpath(path: &str, context: &Value) -> Option<Value> {
    let p = path.strip_prefix('$')?;
    let bytes = p.as_bytes();
    // 全量 clone 而非按需借用:JSON Path 段数与深度运行时才确定,逐段借用需把
    // `&Value` 在循环中重绑(每段 as_object/as_array 返回的借用生命周期互相嵌套),
    // 借用检查极难通过;改用拥有的 Value 顺序覆盖,代码直观。代价是 context 顶层
    // 的一次深拷贝——条件求值在 DAG 边上触发,频率低且 context 通常不深,开销可忽略。
    let mut cur: Value = context.clone();
    let mut i = 0usize;

    while i < bytes.len() {
        match bytes[i] {
            b'.' => {
                i += 1;
                let (key, next) = consume_key(p, i)?;
                i = next;
                cur = cur.as_object().and_then(|m| m.get(&key).cloned())?;
            }
            b'[' => {
                i += 1;
                while i < bytes.len() && bytes[i].is_ascii_whitespace() {
                    i += 1;
                }
                if i >= bytes.len() {
                    return None;
                }
                if bytes[i] == b'\'' {
                    let (key, next) = consume_quoted(p, i)?;
                    i = next;
                    while i < bytes.len() && bytes[i].is_ascii_whitespace() {
                        i += 1;
                    }
                    if i >= bytes.len() || bytes[i] != b']' {
                        return None;
                    }
                    i += 1;
                    cur = cur.as_object().and_then(|m| m.get(&key).cloned())?;
                } else {
                    let start = i;
                    while i < bytes.len() && bytes[i] != b']' {
                        i += 1;
                    }
                    let idx_str = p[start..i].trim();
                    let idx: isize = idx_str.parse().ok()?;
                    i += 1; // 跳过 ]
                    let arr = cur.as_array()?;
                    let len = arr.len() as isize;
                    let real = if idx < 0 { len + idx } else { idx };
                    if real < 0 || real >= len {
                        return None;
                    }
                    cur = arr.get(real as usize).cloned()?;
                }
            }
            c if c.is_ascii_whitespace() => {
                i += 1;
            }
            _ => return None,
        }
    }
    Some(cur)
}

/// 取一段点路径的键(到下一个 `.`/`[`/行尾),返回 (key, 下一个待处理位置)。
fn consume_key(s: &str, start: usize) -> Option<(String, usize)> {
    let bytes = s.as_bytes();
    let mut i = start;
    while i < bytes.len() && bytes[i] != b'.' && bytes[i] != b'[' {
        i += 1;
    }
    let key = s[start..i].trim();
    if key.is_empty() {
        return None;
    }
    Some((key.to_string(), i))
}

/// 取单引号字符串(起始位置指向开引号 `'`),内部 `''` 转义为单引号。
/// 返回 (内容, 闭引号后位置)。
///
/// 实现要点:先扫描定位闭引号的字节位置,再对原始切片整体取出内容,而非逐字节
/// `bytes[i] as char` 累加。原因:单引号 `'` 是 ASCII 单字节字符,从开引号到闭引号
/// 之间的字节范围天然落在 UTF-8 字符边界上,整体切片能完整保留多字节字符(中文/emoji);
/// 逐字节 `as char` 会把每个字节当独立码点,破坏多字节 UTF-8 序列致乱码。
fn consume_quoted(s: &str, start: usize) -> Option<(String, usize)> {
    let bytes = s.as_bytes();
    if start >= bytes.len() || bytes[start] != b'\'' {
        return None;
    }
    // 扫描定位真正的闭引号:遇到 `''` 视为转义(跳过),单个 `'` 才是闭引号
    let mut i = start + 1;
    let content_start = i;
    while i < bytes.len() {
        if bytes[i] == b'\'' {
            // 检测转义 ''
            if i + 1 < bytes.len() && bytes[i + 1] == b'\'' {
                i += 2; // 跳过转义的两引号,继续找闭引号
                continue;
            }
            // 闭引号找到:content_start..i 是引号内的原始字节段(落在 UTF-8 边界)
            let raw = &s[content_start..i];
            // 内部 `''` 转义为单引号:整段替换(无转义时直接 clone 原文,零额外分配开销仅一次)
            let content = raw.replace("''", "'");
            return Some((content, i + 1));
        }
        i += 1;
    }
    None // 未闭合引号
}

// 历史:曾设计「借用或拥有的 Value 视图」类型以避免逐段 clone,后弃用——
// eval_jsonpath 改为直接 clone(见上方实现内注释)。放弃借用优化的理由:JSON Path
// 通常只有少数几段,每段 clone 一个 serde_json::Value 的开销可忽略,换取代码可读性
// 与借用检查通过。此段不再对应任何类型定义,仅作设计取舍的历史说明保留。

// ============================================================================
// Tokenizer —— 把表达式切成 Token 流
// ============================================================================

#[derive(Debug, Clone, PartialEq)]
enum Token {
    Bool(bool),
    Number(f64),
    Str(String),
    Path(String),
    /// `==` `!=` `>` `>=` `<` `<=` `contains`
    Cmp(CmpOp),
    And,
    Or,
    Not,
    LParen,
    RParen,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum CmpOp {
    Eq,
    Ne,
    Gt,
    Ge,
    Lt,
    Le,
    Contains,
}

fn tokenize(s: &str) -> Result<Vec<Token>, ()> {
    let bytes = s.as_bytes();
    let mut toks = Vec::new();
    let mut i = 0usize;

    while i < bytes.len() {
        // 略空白
        if bytes[i].is_ascii_whitespace() {
            i += 1;
            continue;
        }
        match bytes[i] {
            b'(' => {
                toks.push(Token::LParen);
                i += 1;
            }
            b')' => {
                toks.push(Token::RParen);
                i += 1;
            }
            b'\'' => {
                let (val, next) = consume_quoted(s, i).ok_or(())?;
                toks.push(Token::Str(val));
                i = next;
            }
            b'$' => {
                // JSON Path:到下一个空白或比较符或括号外
                let start = i;
                i += 1;
                while i < bytes.len() {
                    let c = bytes[i];
                    // 遇空白 / 逻辑词边界 / 比较符 / 括号 停止
                    if c.is_ascii_whitespace() || c == b'(' || c == b')' {
                        break;
                    }
                    // 比较运算符起始
                    if c == b'=' || c == b'!' || c == b'>' || c == b'<' {
                        break;
                    }
                    // [ 段内允许,但 ] 后若跟字母数字属下一个 token(罕见,简化:整体吃掉)
                    i += 1;
                }
                toks.push(Token::Path(s[start..i].to_string()));
            }
            b'=' => {
                if i + 1 < bytes.len() && bytes[i + 1] == b'=' {
                    toks.push(Token::Cmp(CmpOp::Eq));
                    i += 2;
                } else {
                    return Err(()); // 单 = 非法
                }
            }
            b'!' => {
                if i + 1 < bytes.len() && bytes[i + 1] == b'=' {
                    toks.push(Token::Cmp(CmpOp::Ne));
                    i += 2;
                } else {
                    return Err(()); // 单 ! 非法(不支持 C 风格!)
                }
            }
            b'>' => {
                if i + 1 < bytes.len() && bytes[i + 1] == b'=' {
                    toks.push(Token::Cmp(CmpOp::Ge));
                    i += 2;
                } else {
                    toks.push(Token::Cmp(CmpOp::Gt));
                    i += 1;
                }
            }
            b'<' => {
                if i + 1 < bytes.len() && bytes[i + 1] == b'=' {
                    toks.push(Token::Cmp(CmpOp::Le));
                    i += 2;
                } else {
                    toks.push(Token::Cmp(CmpOp::Lt));
                    i += 1;
                }
            }
            // 数字字面量(含负号起始;正号省略)。注意:`and/or/not/true/false` 不会被
            // 数字分支吃掉,因为它们以字母开头走下面的字母分支。
            b'-' | b'0'..=b'9' => {
                let start = i;
                if bytes[i] == b'-' {
                    i += 1;
                }
                let mut saw_digit = false;
                while i < bytes.len()
                    && (bytes[i].is_ascii_digit() || bytes[i] == b'.')
                {
                    saw_digit = true;
                    i += 1;
                }
                if !saw_digit {
                    return Err(()); // 仅 `-` 非法
                }
                let num: f64 = s[start..i].parse().map_err(|_| ())?;
                toks.push(Token::Number(num));
            }
            // 字母起始:关键字 or/and/not/true/false 或 contains
            _ => {
                let start = i;
                while i < bytes.len()
                    && (bytes[i].is_ascii_alphanumeric() || bytes[i] == b'_')
                {
                    i += 1;
                }
                let word = &s[start..i];
                match word {
                    "true" => toks.push(Token::Bool(true)),
                    "false" => toks.push(Token::Bool(false)),
                    "and" => toks.push(Token::And),
                    "or" => toks.push(Token::Or),
                    "not" => toks.push(Token::Not),
                    "contains" => toks.push(Token::Cmp(CmpOp::Contains)),
                    // 未识别关键字:保守起见视为非法(tokenize 失败 → evaluate false)
                    _ => return Err(()),
                }
            }
        }
    }
    Ok(toks)
}

// ============================================================================
// Parser —— 递归下降,优先级 or < and < not < 比较 < 操作数
// ============================================================================

struct Parser<'a> {
    toks: Vec<Token>,
    pos: usize,
    ctx: &'a Value,
}

impl<'a> Parser<'a> {
    fn peek(&self) -> Option<&Token> {
        self.toks.get(self.pos)
    }

    fn bump(&mut self) -> Option<Token> {
        let t = self.toks.get(self.pos).cloned();
        if t.is_some() {
            self.pos += 1;
        }
        t
    }

    /// or := and ( 'or' and )*
    fn parse_or(&mut self) -> Result<bool, ()> {
        let mut left = self.parse_and()?;
        while let Some(Token::Or) = self.peek() {
            self.bump();
            // 注意:此处并非真正短路求值。右侧 parse_and() 必须无条件执行——
            // 递归下降解析器需消费右侧 token 才能正确推进 pos(否则残留 token 会让
            // 上层误判为非法表达式)。`||` 仅做最终布尔合并;本引擎求值无副作用,
            // 右侧即使结果被丢弃也无害。
            let right = self.parse_and()?;
            left = left || right;
        }
        Ok(left)
    }

    /// and := not ( 'and' not )*
    fn parse_and(&mut self) -> Result<bool, ()> {
        let mut left = self.parse_not()?;
        while let Some(Token::And) = self.peek() {
            self.bump();
            // 同 parse_or:右侧 parse_not() 必须无条件执行以推进 pos,`&&` 仅做
            // 最终布尔合并,非短路求值(引擎无副作用)。
            let right = self.parse_not()?;
            left = left && right;
        }
        Ok(left)
    }

    /// not := 'not' not | comparison
    fn parse_not(&mut self) -> Result<bool, ()> {
        if let Some(Token::Not) = self.peek() {
            self.bump();
            let v = self.parse_not()?;
            return Ok(!v);
        }
        self.parse_comparison()
    }

    /// comparison := operand ( cmpop operand )?
    ///
    /// 无比较运算符时:operand 自身需为布尔语义(JSON Path 取到 bool、或布尔字面量);
    /// 否则视为非布尔(保守 false)。
    fn parse_comparison(&mut self) -> Result<bool, ()> {
        let left = self.parse_operand()?;
        match self.peek() {
            Some(Token::Cmp(op)) => {
                let op = *op;
                self.bump();
                let right = self.parse_operand()?;
                Ok(eval_cmp(op, &left, &right))
            }
            _ => {
                // 单操作数:仅布尔字面量或 JSON Path 指向 bool 为 true;其余保守 false
                Ok(left.as_bool().unwrap_or(false))
            }
        }
    }

    /// operand := '(' or ')' | bool | number | str | path
    fn parse_operand(&mut self) -> Result<Value, ()> {
        match self.bump() {
            Some(Token::LParen) => {
                let v = self.parse_or()?;
                // 期待闭括号
                match self.bump() {
                    Some(Token::RParen) => Ok(Value::Bool(v)),
                    _ => Err(()),
                }
            }
            Some(Token::Bool(b)) => Ok(Value::Bool(b)),
            Some(Token::Number(n)) => Ok(serde_json::json!(n)),
            Some(Token::Str(s)) => Ok(Value::String(s)),
            Some(Token::Path(p)) => {
                // JSON Path 求值失败 → Null(后续比较保守 false)
                Ok(eval_jsonpath(&p, self.ctx).unwrap_or(Value::Null))
            }
            _ => Err(()),
        }
    }
}

/// 比较求值。任一侧类型不兼容 → false(保守)。
fn eval_cmp(op: CmpOp, left: &Value, right: &Value) -> bool {
    match op {
        CmpOp::Eq => json_eq(left, right),
        CmpOp::Ne => !json_eq(left, right),
        CmpOp::Gt | CmpOp::Ge | CmpOp::Lt | CmpOp::Le => {
            let cmp = num_cmp(left, right);
            match (op, cmp) {
                (CmpOp::Gt, Some(o)) => o.is_gt(),
                (CmpOp::Ge, Some(o)) => o.is_ge(),
                (CmpOp::Lt, Some(o)) => o.is_lt(),
                (CmpOp::Le, Some(o)) => o.is_le(),
                _ => false,
            }
        }
        CmpOp::Contains => json_contains(left, right),
    }
}

/// 相等比较:数值按数值比(string "1" 不等于 number 1,避免隐式转换陷阱),
/// 其余按 serde_json Value 相等。布尔与数字需类型对齐(serde_json bool != number)。
fn json_eq(left: &Value, right: &Value) -> bool {
    // 两端均数值(含 i64/u64/f64):数值比较(1.0 == 1)
    if let (Some(a), Some(b)) = (as_f64(left), as_f64(right)) {
        return (a - b).abs() < f64::EPSILON;
    }
    left == right
}

/// 数值比较。两端需均可转 f64(数字字面量、JSON number),否则 None(保守 false)。
fn num_cmp(left: &Value, right: &Value) -> Option<std::cmp::Ordering> {
    let a = as_f64(left)?;
    let b = as_f64(right)?;
    a.partial_cmp(&b)
}

fn as_f64(v: &Value) -> Option<f64> {
    match v {
        Value::Number(n) => n.as_f64(),
        _ => None,
    }
}

/// contains:
/// - 左值为字符串、右值为字符串 → 子串包含
/// - 左值为数组 → 任一元素 json_eq 右值
/// - 其余 → false
fn json_contains(left: &Value, right: &Value) -> bool {
    match left {
        Value::String(s) => right
            .as_str()
            .map(|r| s.contains(r))
            .unwrap_or(false),
        Value::Array(arr) => arr.iter().any(|e| json_eq(e, right)),
        _ => false,
    }
}

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

    // --------------------------------------------------------------------
    // 字面量与向后兼容(原有 7 个用例语义保持)
    // --------------------------------------------------------------------

    #[test]
    fn test_true_literal_returns_true() {
        assert_eq!(ConditionEngine::evaluate("true", &json!({})).unwrap(), true);
    }

    #[test]
    fn test_false_literal_returns_false() {
        assert_eq!(ConditionEngine::evaluate("false", &json!({})).unwrap(), false);
    }

    #[test]
    fn test_unsupported_expression_defaults_to_false() {
        // 历史用例:非法表达式(单 = 等非法 token)保守 false
        // 注:增强后 "$.status == 'completed'" 已合法,改用真正非法的表达式
        assert_eq!(
            ConditionEngine::evaluate("= =", &json!({})).unwrap(),
            false
        );
    }

    #[test]
    fn test_whitespace_is_trimmed() {
        assert_eq!(
            ConditionEngine::evaluate("   true   ", &json!({})).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("\tfalse\n", &json!({})).unwrap(),
            false
        );
    }

    #[test]
    fn test_empty_string_defaults_to_false() {
        assert_eq!(ConditionEngine::evaluate("", &json!({})).unwrap(), false);
        assert_eq!(ConditionEngine::evaluate("   ", &json!({})).unwrap(), false);
    }

    #[test]
    fn test_case_sensitive_not_matched() {
        // True/FALSE 仍非合法布尔字面量(只认小写 true/false)
        assert_eq!(ConditionEngine::evaluate("True", &json!({})).unwrap(), false);
        assert_eq!(ConditionEngine::evaluate("FALSE", &json!({})).unwrap(), false);
    }

    #[test]
    fn test_arbitrary_string_defaults_to_false() {
        // 未识别关键字(yes / completed)→ tokenize 失败 → false
        assert_eq!(ConditionEngine::evaluate("yes", &json!({})).unwrap(), false);
        assert_eq!(ConditionEngine::evaluate("completed", &json!({})).unwrap(), false);
        // 裸数字(非布尔语义)→ 单操作数非 bool → false
        assert_eq!(ConditionEngine::evaluate("1", &json!({})).unwrap(), false);
    }

    // --------------------------------------------------------------------
    // 一、JSON Path 求值
    // --------------------------------------------------------------------

    #[test]
    fn jsonpath_eq_string_literal() {
        let ctx = json!({ "status": "completed" });
        assert_eq!(
            ConditionEngine::evaluate("$.status == 'completed'", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.status == 'failed'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn jsonpath_nested_dot() {
        let ctx = json!({ "result": { "code": 200 } });
        assert_eq!(
            ConditionEngine::evaluate("$.result.code == 200", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn jsonpath_array_index() {
        let ctx = json!({ "tags": ["ai", "rust"] });
        assert_eq!(
            ConditionEngine::evaluate("$.tags[0] == 'ai'", &ctx).unwrap(),
            true
        );
        // 负数下标从尾部
        assert_eq!(
            ConditionEngine::evaluate("$.tags[-1] == 'rust'", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn jsonpath_missing_path_defaults_false() {
        // 路径不存在 → Null == 'completed' → false(保守)
        let ctx = json!({ "status": "ok" });
        assert_eq!(
            ConditionEngine::evaluate("$.missing == 'x'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn jsonpath_bool_value_as_operand() {
        // JSON Path 指向 bool,可作单操作数布尔求值
        let ctx = json!({ "approved": true });
        assert_eq!(
            ConditionEngine::evaluate("$.approved", &ctx).unwrap(),
            true
        );
        // 非 bool 字段作单操作数 → false(字符串非布尔语义)
        let ctx2 = json!({ "status": "ok" });
        assert_eq!(
            ConditionEngine::evaluate("$.status", &ctx2).unwrap(),
            false
        );
    }

    // --------------------------------------------------------------------
    // 二、比较运算符(==/!=/>/</>=/<=)
    // --------------------------------------------------------------------

    #[test]
    fn numeric_gt_lt() {
        let ctx = json!({ "count": 15 });
        assert_eq!(
            ConditionEngine::evaluate("$.count > 10", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.count < 10", &ctx).unwrap(),
            false
        );
        assert_eq!(
            ConditionEngine::evaluate("$.count >= 15", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.count <= 14", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn numeric_negative_and_decimal() {
        let ctx = json!({ "temp": -3.5 });
        assert_eq!(
            ConditionEngine::evaluate("$.temp < 0", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.temp == -3.5", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn ne_operator() {
        let ctx = json!({ "status": "ok" });
        assert_eq!(
            ConditionEngine::evaluate("$.status != 'failed'", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.status != 'ok'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn non_numeric_gt_defaults_false() {
        // 字符串 > 数字:类型不兼容 → 保守 false
        let ctx = json!({ "name": "abc" });
        assert_eq!(
            ConditionEngine::evaluate("$.name > 10", &ctx).unwrap(),
            false
        );
    }

    // --------------------------------------------------------------------
    // 三、contains
    // --------------------------------------------------------------------

    #[test]
    fn contains_substring() {
        let ctx = json!({ "msg": "hello world" });
        assert_eq!(
            ConditionEngine::evaluate("$.msg contains 'world'", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.msg contains 'xyz'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn contains_array_element() {
        let ctx = json!({ "tags": ["ai", "rust", "devflow"] });
        assert_eq!(
            ConditionEngine::evaluate("$.tags contains 'rust'", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.tags contains 'go'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn contains_numeric_in_array() {
        // 数组 contains 数字(数值相等判定,1 == 1.0)
        let ctx = json!({ "nums": [1, 2, 3] });
        assert_eq!(
            ConditionEngine::evaluate("$.nums contains 2", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn contains_non_string_non_array_defaults_false() {
        let ctx = json!({ "n": 100 });
        // 数字 contains ... 无意义 → false
        assert_eq!(
            ConditionEngine::evaluate("$.n contains '1'", &ctx).unwrap(),
            false
        );
    }

    // --------------------------------------------------------------------
    // 四、逻辑组合 and / or / not
    // --------------------------------------------------------------------

    #[test]
    fn logical_and() {
        let ctx = json!({ "a": true, "b": false });
        assert_eq!(
            ConditionEngine::evaluate("$.a and $.b", &ctx).unwrap(),
            false
        );
        let ctx2 = json!({ "a": true, "b": true });
        assert_eq!(
            ConditionEngine::evaluate("$.a and $.b", &ctx2).unwrap(),
            true
        );
    }

    #[test]
    fn logical_or() {
        let ctx = json!({ "a": false, "b": true });
        assert_eq!(
            ConditionEngine::evaluate("$.a or $.b", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn logical_not() {
        let ctx = json!({ "approved": false });
        assert_eq!(
            ConditionEngine::evaluate("not $.approved", &ctx).unwrap(),
            true
        );
        let ctx2 = json!({ "approved": true });
        assert_eq!(
            ConditionEngine::evaluate("not $.approved", &ctx2).unwrap(),
            false
        );
    }

    #[test]
    fn and_or_precedence() {
        // and 优先级高于 or:true or (false and false) → true
        let ctx = json!({});
        assert_eq!(
            ConditionEngine::evaluate("true or false and false", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn not_precedence_over_and() {
        // not 高于 and:not false and not false → true and true → true
        let ctx = json!({});
        assert_eq!(
            ConditionEngine::evaluate("not false and not false", &ctx).unwrap(),
            true
        );
    }

    // --------------------------------------------------------------------
    // 五、嵌套括号 + 综合
    // --------------------------------------------------------------------

    #[test]
    fn nested_parens() {
        let ctx = json!({});
        // (true or false) and (false or true) → true and true → true
        assert_eq!(
            ConditionEngine::evaluate("(true or false) and (false or true)", &ctx).unwrap(),
            true
        );
        // not (true and true) → false
        assert_eq!(
            ConditionEngine::evaluate("not (true and true)", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn complex_realworld_expression() {
        // 综合场景:状态完成 且 (分数 >= 80 或 含 vip 标签)且 未取消
        let ctx = json!({
            "status": "completed",
            "score": 85,
            "tags": ["vip", "ai"],
            "cancelled": false
        });
        let expr = "$.status == 'completed' and ($.score >= 80 or $.tags contains 'vip') and not $.cancelled";
        assert_eq!(
            ConditionEngine::evaluate(expr, &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn unbalanced_parens_defaults_false() {
        // 括号不闭合 → parse 失败 → 保守 false
        assert_eq!(
            ConditionEngine::evaluate("(true and false", &json!({})).unwrap(),
            false
        );
    }

    #[test]
    fn unclosed_quote_defaults_false() {
        assert_eq!(
            ConditionEngine::evaluate("$.s == 'abc", &json!({"s":"x"})).unwrap(),
            false
        );
    }

    // --------------------------------------------------------------------
    // 六、多字节 UTF-8(中文 key/值、emoji)与转义——回归 consume_quoted 逐字节 bug
    // --------------------------------------------------------------------

    #[test]
    fn jsonpath_chinese_key_and_value() {
        // 中文 key + 中文值:验证 consume_quoted 整体切片保留 UTF-8(逐字节 as char 会乱码)
        let ctx = json!({ "状态": "已完成" });
        assert_eq!(
            ConditionEngine::evaluate("$.状态 == '已完成'", &ctx).unwrap(),
            true
        );
        assert_eq!(
            ConditionEngine::evaluate("$.状态 == '失败'", &ctx).unwrap(),
            false
        );
    }

    #[test]
    fn jsonpath_bracket_chinese_key() {
        // $['中文'] 单引号括号键含中文值,直接考验 consume_quoted 多字节处理
        let ctx = json!({ "中文": "成功" });
        assert_eq!(
            ConditionEngine::evaluate("$['中文'] == '成功'", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn jsonpath_emoji_value() {
        // emoji(4 字节 UTF-8 序列)作字面量值
        let ctx = json!({ "flag": "🚀" });
        assert_eq!(
            ConditionEngine::evaluate("$.flag == '🚀'", &ctx).unwrap(),
            true
        );
    }

    #[test]
    fn single_quote_escaped_inside_literal() {
        // 内部 '' 转义为单引号:it''s → it's
        let ctx = json!({ "msg": "it's done" });
        assert_eq!(
            ConditionEngine::evaluate("$.msg == 'it''s done'", &ctx).unwrap(),
            true
        );
    }
}
