use std::collections::HashMap;

use crate::error::{WorkflowError, WorkflowResult};

/// 简单表达式求值器。
///
/// 支持的比较运算符：>, >=, <, <=, ==, !=
/// 支持 && 和 || 逻辑运算。
/// 操作数可以是变量名（从 variables map 查找）或字面量（数字、字符串）。
///
/// 示例：
/// - `amount > 1000`
/// - `status == "approved"`
/// - `score >= 60 && attendance > 80`
pub struct ExpressionEvaluator;

impl ExpressionEvaluator {
    /// 求值单个条件表达式。
    ///
    /// 表达式格式: `{left} {op} {right}` 或复合表达式 `{expr1} && {expr2}`
    pub fn eval(
        expr: &str,
        variables: &HashMap<String, serde_json::Value>,
    ) -> WorkflowResult<bool> {
        let expr = expr.trim();

        // 处理逻辑 OR
        if let Some(idx) = Self::find_logical_op(expr, "||") {
            let left = &expr[..idx];
            let right = &expr[idx + 2..];
            return Ok(Self::eval(left, variables)? || Self::eval(right, variables)?);
        }

        // 处理逻辑 AND
        if let Some(idx) = Self::find_logical_op(expr, "&&") {
            let left = &expr[..idx];
            let right = &expr[idx + 2..];
            return Ok(Self::eval(left, variables)? && Self::eval(right, variables)?);
        }

        // 处理单个比较表达式
        Self::eval_comparison(expr, variables)
    }

    /// 查找逻辑运算符位置，跳过引号内的内容。
    fn find_logical_op(expr: &str, op: &str) -> Option<usize> {
        let mut in_string = false;
        let mut string_char = ' ';
        let chars: Vec<char> = expr.chars().collect();
        let op_chars: Vec<char> = op.chars().collect();
        let op_len = op_chars.len();

        for i in 0..chars.len().saturating_sub(op_len - 1) {
            let c = chars[i];

            if !in_string && (c == '"' || c == '\'') {
                in_string = true;
                string_char = c;
                continue;
            }
            if in_string && c == string_char {
                in_string = false;
                continue;
            }

            if in_string {
                continue;
            }

            if chars[i..].starts_with(&op_chars) {
                return Some(i);
            }
        }
        None
    }

    /// 求值单个比较表达式。
    fn eval_comparison(
        expr: &str,
        variables: &HashMap<String, serde_json::Value>,
    ) -> WorkflowResult<bool> {
        let operators = [">=", "<=", "!=", "==", ">", "<"];

        for op in &operators {
            if let Some(idx) = Self::find_comparison_op(expr, op) {
                let left = expr[..idx].trim();
                let right = expr[idx + op.len()..].trim();

                let left_val = Self::resolve_value(left, variables)?;
                let right_val = Self::resolve_value(right, variables)?;

                return Self::compare(&left_val, &right_val, op);
            }
        }

        Err(WorkflowError::ExpressionError(format!(
            "无法解析表达式: '{}'",
            expr
        )))
    }

    /// 查找比较运算符位置，跳过引号内的内容。
    fn find_comparison_op(expr: &str, op: &str) -> Option<usize> {
        let mut in_string = false;
        let mut string_char = ' ';
        let bytes = expr.as_bytes();
        let op_bytes = op.as_bytes();
        let op_len = op_bytes.len();

        for i in 0..bytes.len().saturating_sub(op_len - 1) {
            let c = bytes[i] as char;

            if !in_string && (c == '"' || c == '\'') {
                in_string = true;
                string_char = c;
                continue;
            }
            if in_string && c == string_char {
                in_string = false;
                continue;
            }

            if in_string {
                continue;
            }

            if bytes[i..].starts_with(op_bytes) {
                // 确保不是被嵌在其他运算符里（如 != 中的 =）
                // 对于 > 和 < 检查后面不是 = 或 >
                if op == ">" || op == "<" {
                    if i + op_len < bytes.len() {
                        let next = bytes[i + op_len] as char;
                        if next == '=' || (op == ">" && next == '>') {
                            continue;
                        }
                    }
                    // 也检查前面不是 ! 或 = 或 < 或 >
                    if i > 0 {
                        let prev = bytes[i - 1] as char;
                        if prev == '!' || prev == '=' || prev == '<' || prev == '>' {
                            continue;
                        }
                    }
                }
                // 对于 ==, >=, <=, != 确保前面不是 ! 或 = (避免匹配到 == 中的第二个 =)
                // 这已经通过从长到短匹配处理了
                return Some(i);
            }
        }
        None
    }

    /// 解析值：字符串字面量、数字字面量或变量引用。
    fn resolve_value(
        token: &str,
        variables: &HashMap<String, serde_json::Value>,
    ) -> WorkflowResult<serde_json::Value> {
        let token = token.trim();

        // 字符串字面量
        if (token.starts_with('"') && token.ends_with('"'))
            || (token.starts_with('\'') && token.ends_with('\''))
        {
            return Ok(serde_json::Value::String(
                token[1..token.len() - 1].to_string(),
            ));
        }

        // 数字字面量
        if let Ok(n) = token.parse::<i64>() {
            return Ok(serde_json::Value::Number(n.into()));
        }
        if let Ok(f) = token.parse::<f64>()
            && let Some(n) = serde_json::Number::from_f64(f)
        {
            return Ok(serde_json::Value::Number(n));
        }

        // 布尔字面量
        if token == "true" {
            return Ok(serde_json::Value::Bool(true));
        }
        if token == "false" {
            return Ok(serde_json::Value::Bool(false));
        }

        // 变量引用
        if let Some(val) = variables.get(token) {
            return Ok(val.clone());
        }

        Err(WorkflowError::ExpressionError(format!(
            "未知的变量或值: '{}'",
            token
        )))
    }

    /// 比较两个 JSON 值。
    fn compare(
        left: &serde_json::Value,
        right: &serde_json::Value,
        op: &str,
    ) -> WorkflowResult<bool> {
        match op {
            "==" => Ok(Self::values_equal(left, right)),
            "!=" => Ok(!Self::values_equal(left, right)),
            ">" => Ok(Self::values_compare(left, right)? == std::cmp::Ordering::Greater),
            ">=" => Ok(Self::values_compare(left, right)? != std::cmp::Ordering::Less),
            "<" => Ok(Self::values_compare(left, right)? == std::cmp::Ordering::Less),
            "<=" => Ok(Self::values_compare(left, right)? != std::cmp::Ordering::Greater),
            _ => Err(WorkflowError::ExpressionError(format!(
                "不支持的比较运算符: '{}'",
                op
            ))),
        }
    }

    fn values_equal(left: &serde_json::Value, right: &serde_json::Value) -> bool {
        // 数值比较：允许整数和浮点数互比
        if left.is_number() && right.is_number() {
            return left.as_f64() == right.as_f64();
        }
        left == right
    }

    fn values_compare(
        left: &serde_json::Value,
        right: &serde_json::Value,
    ) -> WorkflowResult<std::cmp::Ordering> {
        if left.is_number() && right.is_number() {
            let l = left.as_f64().unwrap_or(0.0);
            let r = right.as_f64().unwrap_or(0.0);
            return Ok(l.partial_cmp(&r).unwrap_or(std::cmp::Ordering::Equal));
        }

        if let (Some(l), Some(r)) = (left.as_str(), right.as_str()) {
            return Ok(l.cmp(r));
        }

        Err(WorkflowError::ExpressionError(format!(
            "无法比较 {:?} 和 {:?}",
            left, right
        )))
    }
}

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

    fn make_vars() -> HashMap<String, serde_json::Value> {
        let mut m = HashMap::new();
        m.insert("amount".to_string(), json!(1500));
        m.insert("status".to_string(), json!("approved"));
        m.insert("score".to_string(), json!(85));
        m.insert("name".to_string(), json!("Alice"));
        m.insert("active".to_string(), json!(true));
        m
    }

    #[test]
    fn test_number_greater_than() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount > 1000", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount > 2000", &vars).unwrap());
    }

    #[test]
    fn test_number_less_than() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount < 2000", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount < 1000", &vars).unwrap());
    }

    #[test]
    fn test_number_equals() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount == 1500", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount == 1000", &vars).unwrap());
    }

    #[test]
    fn test_string_equals() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("status == \"approved\"", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("status == \"rejected\"", &vars).unwrap());
    }

    #[test]
    fn test_string_not_equals() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("status != \"rejected\"", &vars).unwrap());
    }

    #[test]
    fn test_greater_or_equal() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount >= 1500", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("amount >= 1000", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount >= 2000", &vars).unwrap());
    }

    #[test]
    fn test_logical_and() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount > 1000 && score > 80", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount > 2000 && score > 80", &vars).unwrap());
    }

    #[test]
    fn test_logical_or() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount > 2000 || score > 80", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount > 2000 || score > 90", &vars).unwrap());
    }

    #[test]
    fn test_unknown_variable() {
        let vars = make_vars();
        let result = ExpressionEvaluator::eval("unknown > 0", &vars);
        assert!(result.is_err());
    }

    #[test]
    fn test_invalid_expression() {
        let vars = make_vars();
        let result = ExpressionEvaluator::eval("justavariable", &vars);
        assert!(result.is_err());
    }

    // ---- 扩展边界测试 ----

    #[test]
    fn test_less_or_equal() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount <= 1500", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("amount <= 2000", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount <= 1000", &vars).unwrap());
    }

    #[test]
    fn test_boolean_equality() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("active == true", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("active == false", &vars).unwrap());
    }

    #[test]
    fn test_string_literal_with_single_quotes() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("status == 'approved'", &vars).unwrap());
    }

    #[test]
    fn test_float_comparison() {
        let mut vars = HashMap::new();
        vars.insert("temperature".to_string(), json!(36.5));
        assert!(ExpressionEvaluator::eval("temperature >= 36.0", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("temperature < 37.0", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("temperature > 37.5", &vars).unwrap());
    }

    #[test]
    fn test_integer_float_cross_comparison() {
        let mut vars = HashMap::new();
        vars.insert("val".to_string(), json!(10));
        assert!(ExpressionEvaluator::eval("val == 10.0", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("val >= 9.5", &vars).unwrap());
    }

    #[test]
    fn test_string_comparison_lexicographic() {
        let vars = make_vars();
        // name = "Alice"
        assert!(!ExpressionEvaluator::eval("name > \"Alice\"", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("name >= \"Alice\"", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("name < \"Bob\"", &vars).unwrap());
        assert!(ExpressionEvaluator::eval("name == \"Alice\"", &vars).unwrap());
    }

    #[test]
    fn test_compound_and_or() {
        let vars = make_vars();
        // amount > 1000 (true) && score > 80 (true) || amount > 3000 (false)
        // OR 先绑定，所以是 amount>1000 && score>80 (true) || amount>3000 (false)
        // 注意：当前实现从左到右先匹配 ||，所以实际解析为:
        // amount > 1000 && score > 80 || amount > 3000
        // find_logical_op 先找 || → split at ||
        // left = "amount > 1000 && score > 80", right = "amount > 3000"
        // left = true, right = false → true || false = true
        assert!(
            ExpressionEvaluator::eval("amount > 1000 && score > 80 || amount > 3000", &vars)
                .unwrap()
        );
    }

    #[test]
    fn test_compound_all_false() {
        let vars = make_vars();
        assert!(!ExpressionEvaluator::eval("amount > 2000 && score > 90", &vars).unwrap());
    }

    #[test]
    fn test_number_not_equals() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("amount != 1000", &vars).unwrap());
        assert!(!ExpressionEvaluator::eval("amount != 1500", &vars).unwrap());
    }

    #[test]
    fn test_expression_with_extra_whitespace() {
        let vars = make_vars();
        assert!(ExpressionEvaluator::eval("  amount  >  1000  ", &vars).unwrap());
    }

    #[test]
    fn test_unresolvable_variable_returns_error() {
        let vars = HashMap::new();
        let result = ExpressionEvaluator::eval("missing_var > 10", &vars);
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("未知的变量"));
    }

    #[test]
    fn test_empty_expression_returns_error() {
        let vars = HashMap::new();
        let result = ExpressionEvaluator::eval("", &vars);
        assert!(result.is_err());
    }
}
