//! Tree-walking interpreter for the Lux language with algebraic effects

#![allow(dead_code, unused_variables)]

use crate::ast::*;
use crate::diagnostics::{Diagnostic, ErrorCode, Severity};
use rand::Rng;
use postgres::{Client as PgClient, NoTls};
use rusqlite::Connection;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

/// Built-in function identifier
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinFn {
    // List operations
    ListMap,
    ListFilter,
    ListFold,
    ListHead,
    ListTail,
    ListConcat,
    ListReverse,
    ListLength,
    ListGet,
    ListRange,
    ListForEach,

    // String operations
    StringSplit,
    StringJoin,
    StringTrim,
    StringContains,
    StringReplace,
    StringLength,
    StringChars,
    StringLines,
    StringParseInt,
    StringParseFloat,

    // Option operations
    OptionMap,
    OptionFlatMap,
    OptionGetOrElse,
    OptionIsSome,
    OptionIsNone,

    // Result operations
    ResultMap,
    ResultFlatMap,
    ResultGetOrElse,
    ResultIsOk,
    ResultIsErr,

    // Utility
    Print,
    ToString,
    TypeOf,

    // Schema Evolution
    Versioned,   // Create versioned value: versioned("TypeName", 1, value)
    Migrate,     // Migrate to version: migrate(versionedValue, targetVersion)
    GetVersion,  // Get version number: getVersion(versionedValue)

    // Math operations
    MathAbs,
    MathMin,
    MathMax,
    MathSqrt,
    MathPow,
    MathFloor,
    MathCeil,
    MathRound,

    // Additional List operations
    ListIsEmpty,
    ListFind,
    ListAny,
    ListAll,
    ListTake,
    ListDrop,

    // Additional String operations
    StringStartsWith,
    StringEndsWith,
    StringToUpper,
    StringToLower,
    StringSubstring,
    StringFromChar,
    StringCharAt,
    StringIndexOf,
    StringLastIndexOf,
    StringRepeat,

    // JSON operations
    JsonParse,
    JsonStringify,
    JsonPrettyPrint,
    JsonGet,
    JsonGetIndex,
    JsonAsString,
    JsonAsNumber,
    JsonAsInt,
    JsonAsBool,
    JsonAsArray,
    JsonIsNull,
    JsonKeys,
    JsonNull,
    JsonBool,
    JsonNumber,
    JsonInt,
    JsonString,
    JsonArray,
    JsonObject,
}

/// Runtime value
#[derive(Debug, Clone)]
pub enum Value {
    Int(i64),
    Float(f64),
    Bool(bool),
    String(String),
    Char(char),
    Unit,
    List(Vec<Value>),
    Tuple(Vec<Value>),
    Record(HashMap<String, Value>),
    Function(Rc<Closure>),
    Handler(Rc<HandlerValue>),
    /// Built-in function
    Builtin(BuiltinFn),
    /// Constructor value (for ADTs)
    Constructor {
        name: String,
        fields: Vec<Value>,
    },
    /// Versioned value (for schema evolution)
    Versioned {
        type_name: String,
        version: u32,
        value: Box<Value>,
    },
    /// JSON value (for JSON parsing/manipulation)
    Json(serde_json::Value),
}

impl Value {
    pub fn type_name(&self) -> &'static str {
        match self {
            Value::Int(_) => "Int",
            Value::Float(_) => "Float",
            Value::Bool(_) => "Bool",
            Value::String(_) => "String",
            Value::Char(_) => "Char",
            Value::Unit => "Unit",
            Value::List(_) => "List",
            Value::Tuple(_) => "Tuple",
            Value::Record(_) => "Record",
            Value::Function(_) => "Function",
            Value::Handler(_) => "Handler",
            Value::Builtin(_) => "Function",
            Value::Constructor { .. } => "Constructor",
            Value::Versioned { .. } => "Versioned",
            Value::Json(_) => "Json",
        }
    }

    /// Unwrap a versioned value to get the inner value
    pub fn unwrap_versioned(&self) -> &Value {
        match self {
            Value::Versioned { value, .. } => value.unwrap_versioned(),
            other => other,
        }
    }

    /// Get version info if this is a versioned value
    pub fn version_info(&self) -> Option<(String, u32)> {
        match self {
            Value::Versioned {
                type_name, version, ..
            } => Some((type_name.clone(), *version)),
            _ => None,
        }
    }

    /// Compare two values for equality (for testing)
    /// Returns true if the values are structurally equal
    pub fn values_equal(a: &Value, b: &Value) -> bool {
        match (a, b) {
            (Value::Int(x), Value::Int(y)) => x == y,
            (Value::Float(x), Value::Float(y)) => (x - y).abs() < f64::EPSILON,
            (Value::Bool(x), Value::Bool(y)) => x == y,
            (Value::String(x), Value::String(y)) => x == y,
            (Value::Char(x), Value::Char(y)) => x == y,
            (Value::Unit, Value::Unit) => true,
            (Value::List(xs), Value::List(ys)) => {
                xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x, y)| Value::values_equal(x, y))
            }
            (Value::Tuple(xs), Value::Tuple(ys)) => {
                xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x, y)| Value::values_equal(x, y))
            }
            (Value::Record(xs), Value::Record(ys)) => {
                xs.len() == ys.len() && xs.iter().all(|(k, v)| {
                    ys.get(k).map(|yv| Value::values_equal(v, yv)).unwrap_or(false)
                })
            }
            (Value::Constructor { name: n1, fields: f1 }, Value::Constructor { name: n2, fields: f2 }) => {
                n1 == n2 && f1.len() == f2.len() && f1.iter().zip(f2.iter()).all(|(x, y)| Value::values_equal(x, y))
            }
            (Value::Versioned { type_name: t1, version: v1, value: val1 },
             Value::Versioned { type_name: t2, version: v2, value: val2 }) => {
                t1 == t2 && v1 == v2 && Value::values_equal(val1, val2)
            }
            (Value::Json(j1), Value::Json(j2)) => j1 == j2,
            // Functions and handlers cannot be compared for equality
            _ => false,
        }
    }
}

/// Trait for extracting typed values from Value
trait TryFromValue: Sized {
    const TYPE_NAME: &'static str;
    fn try_from_value(value: &Value) -> Option<Self>;
}

impl TryFromValue for i64 {
    const TYPE_NAME: &'static str = "Int";
    fn try_from_value(value: &Value) -> Option<Self> {
        match value {
            Value::Int(n) => Some(*n),
            _ => None,
        }
    }
}

impl TryFromValue for f64 {
    const TYPE_NAME: &'static str = "Float";
    fn try_from_value(value: &Value) -> Option<Self> {
        match value {
            Value::Float(n) => Some(*n),
            _ => None,
        }
    }
}

impl TryFromValue for String {
    const TYPE_NAME: &'static str = "String";
    fn try_from_value(value: &Value) -> Option<Self> {
        match value {
            Value::String(s) => Some(s.clone()),
            _ => None,
        }
    }
}

impl TryFromValue for bool {
    const TYPE_NAME: &'static str = "Bool";
    fn try_from_value(value: &Value) -> Option<Self> {
        match value {
            Value::Bool(b) => Some(*b),
            _ => None,
        }
    }
}

impl TryFromValue for Vec<Value> {
    const TYPE_NAME: &'static str = "List";
    fn try_from_value(value: &Value) -> Option<Self> {
        match value {
            Value::List(l) => Some(l.clone()),
            _ => None,
        }
    }
}

impl TryFromValue for Value {
    const TYPE_NAME: &'static str = "any";
    fn try_from_value(value: &Value) -> Option<Self> {
        Some(value.clone())
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Int(n) => write!(f, "{}", n),
            Value::Float(n) => write!(f, "{}", n),
            Value::Bool(b) => write!(f, "{}", b),
            Value::String(s) => write!(f, "\"{}\"", s),
            Value::Char(c) => write!(f, "'{}'", c),
            Value::Unit => write!(f, "()"),
            Value::List(elements) => {
                write!(f, "[")?;
                for (i, e) in elements.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", e)?;
                }
                write!(f, "]")
            }
            Value::Tuple(elements) => {
                write!(f, "(")?;
                for (i, e) in elements.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", e)?;
                }
                write!(f, ")")
            }
            Value::Record(fields) => {
                write!(f, "{{ ")?;
                for (i, (name, value)) in fields.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}: {}", name, value)?;
                }
                write!(f, " }}")
            }
            Value::Function(_) => write!(f, "<function>"),
            Value::Builtin(b) => write!(f, "<builtin:{:?}>", b),
            Value::Handler(_) => write!(f, "<handler>"),
            Value::Constructor { name, fields } => {
                if fields.is_empty() {
                    write!(f, "{}", name)
                } else {
                    write!(f, "{}(", name)?;
                    for (i, field) in fields.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{}", field)?;
                    }
                    write!(f, ")")
                }
            }
            Value::Versioned {
                type_name,
                version,
                value,
            } => {
                write!(f, "{} @v{}", value, version)
            }
            Value::Json(json) => write!(f, "{}", json),
        }
    }
}

/// Function closure
#[derive(Debug)]
pub struct Closure {
    pub params: Vec<String>,
    pub body: Expr,
    pub env: Env,
}

/// Handler value
#[derive(Debug)]
pub struct HandlerValue {
    pub effect: String,
    pub implementations: HashMap<String, HandlerImpl>,
    pub env: Env,
}

/// Environment (lexical scope)
#[derive(Debug, Clone, Default)]
pub struct Env {
    bindings: Rc<RefCell<HashMap<String, Value>>>,
    parent: Option<Box<Env>>,
}

impl Env {
    pub fn new() -> Self {
        Self {
            bindings: Rc::new(RefCell::new(HashMap::new())),
            parent: None,
        }
    }

    pub fn extend(&self) -> Self {
        Self {
            bindings: Rc::new(RefCell::new(HashMap::new())),
            parent: Some(Box::new(self.clone())),
        }
    }

    pub fn define(&self, name: impl Into<String>, value: Value) {
        self.bindings.borrow_mut().insert(name.into(), value);
    }

    pub fn get(&self, name: &str) -> Option<Value> {
        if let Some(value) = self.bindings.borrow().get(name) {
            return Some(value.clone());
        }
        if let Some(ref parent) = self.parent {
            return parent.get(name);
        }
        None
    }
}

/// Runtime error
#[derive(Debug, Clone)]
pub struct RuntimeError {
    pub message: String,
    pub span: Option<Span>,
}

impl fmt::Display for RuntimeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(span) = self.span {
            write!(
                f,
                "Runtime error at {}-{}: {}",
                span.start, span.end, self.message
            )
        } else {
            write!(f, "Runtime error: {}", self.message)
        }
    }
}

impl std::error::Error for RuntimeError {}

impl RuntimeError {
    /// Convert to a rich diagnostic for Elm-style error display
    pub fn to_diagnostic(&self) -> Diagnostic {
        let (code, title, hints) = categorize_runtime_error(&self.message);

        Diagnostic {
            severity: Severity::Error,
            code,
            title,
            message: self.message.clone(),
            span: self.span.unwrap_or_default(),
            hints,
            expected_type: None,
            actual_type: None,
            secondary_spans: Vec::new(),
        }
    }
}

/// Categorize runtime errors to provide better titles, hints, and error codes
fn categorize_runtime_error(message: &str) -> (Option<ErrorCode>, String, Vec<String>) {
    let message_lower = message.to_lowercase();

    if message_lower.contains("undefined variable") {
        (
            Some(ErrorCode::E0301),
            "Undefined Variable".to_string(),
            vec!["Make sure the variable is defined and in scope.".to_string()],
        )
    } else if message_lower.contains("undefined function") || message_lower.contains("function not found") {
        (
            Some(ErrorCode::E0302),
            "Undefined Function".to_string(),
            vec!["Make sure the function is defined and in scope.".to_string()],
        )
    } else if message_lower.contains("undefined") || message_lower.contains("not found") {
        (
            Some(ErrorCode::E0301),
            "Undefined Reference".to_string(),
            vec!["Make sure the name is defined and in scope.".to_string()],
        )
    } else if message_lower.contains("division by zero") || message_lower.contains("divide by zero") {
        (
            None, // Runtime error, not a type error
            "Division by Zero".to_string(),
            vec![
                "Check that the divisor is not zero before dividing.".to_string(),
                "Consider using a guard or match to handle this case.".to_string(),
            ],
        )
    } else if message_lower.contains("type") && message_lower.contains("mismatch") {
        (
            Some(ErrorCode::E0201),
            "Type Mismatch".to_string(),
            vec!["The value has a different type than expected.".to_string()],
        )
    } else if message_lower.contains("effect") && message_lower.contains("unhandled") {
        (
            Some(ErrorCode::E0401),
            "Unhandled Effect".to_string(),
            vec![
                "This effect must be handled before the program can continue.".to_string(),
                "Wrap this code in a 'handle' expression.".to_string(),
            ],
        )
    } else if message_lower.contains("pattern") && message_lower.contains("match") {
        (
            Some(ErrorCode::E0501),
            "Non-exhaustive Pattern".to_string(),
            vec!["Add more patterns to cover all possible cases.".to_string()],
        )
    } else if message_lower.contains("argument") {
        (
            Some(ErrorCode::E0209),
            "Wrong Arguments".to_string(),
            vec!["Check the number and types of arguments provided.".to_string()],
        )
    } else if message_lower.contains("index") || message_lower.contains("bounds") {
        (
            None, // Runtime error
            "Index Out of Bounds".to_string(),
            vec![
                "The index is outside the valid range.".to_string(),
                "Check the length of the collection before accessing.".to_string(),
            ],
        )
    } else {
        (None, "Runtime Error".to_string(), vec![])
    }
}

/// Effect operation request
#[derive(Debug, Clone)]
pub struct EffectRequest {
    pub effect: String,
    pub operation: String,
    pub args: Vec<Value>,
    pub continuation: Continuation,
}

/// Continuation (captured rest of computation)
#[derive(Debug, Clone)]
pub struct Continuation {
    // For simplicity, we'll use a callback-based approach
    // In a real implementation, this would capture the stack
    id: usize,
}

static NEXT_CONT_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);

impl Continuation {
    fn new() -> Self {
        Self {
            id: NEXT_CONT_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
        }
    }
}

/// Result of evaluation (either a value, effect request, or tail call)
pub enum EvalResult {
    Value(Value),
    Effect(EffectRequest),
    /// Tail call optimization: instead of recursing, return the call to be trampolined
    TailCall {
        func: Value,
        args: Vec<Value>,
        span: Span,
    },
    /// Resume from a handler - the value becomes the effect operation's return value
    Resume(Value),
}

/// Effect trace entry for debugging
#[derive(Debug, Clone)]
pub struct EffectTrace {
    pub effect: String,
    pub operation: String,
    pub args: Vec<Value>,
    pub result: Option<Value>,
    pub timestamp_us: u128,
}

/// The interpreter
/// A stored migration function
#[derive(Clone)]
pub struct StoredMigration {
    /// The expression to evaluate for migration
    pub body: Expr,
    /// Environment captured when the migration was defined
    pub env: Env,
}

impl std::fmt::Debug for StoredMigration {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("StoredMigration").finish()
    }
}

pub struct Interpreter {
    global_env: Env,
    /// Stack of active effect handlers (kept for nested handler semantics)
    handler_stack: Vec<Rc<HandlerValue>>,
    /// Evidence map for O(1) handler lookup (evidence passing optimization)
    /// Maps effect name -> handler, updated when entering/exiting run blocks
    evidence: HashMap<String, Rc<HandlerValue>>,
    /// Stored continuations for resumption
    continuations: HashMap<usize, Box<dyn FnOnce(Value) -> Result<EvalResult, RuntimeError>>>,
    /// Effect tracing for debugging
    pub trace_effects: bool,
    /// Collected effect traces
    pub effect_traces: Vec<EffectTrace>,
    /// Start time for timestamps
    start_time: std::time::Instant,
    /// Migration registry: type_name -> (from_version -> to_version -> migration)
    migrations: HashMap<String, HashMap<u32, StoredMigration>>,
    /// Built-in State effect storage (uses RefCell for interior mutability)
    builtin_state: RefCell<Value>,
    /// Built-in Reader effect value (uses RefCell for interior mutability)
    builtin_reader: RefCell<Value>,
    /// Depth of handler context (> 0 means we're inside a handler body where resume is valid)
    in_handler_depth: usize,
    /// HTTP server state (using Arc<Mutex> for thread-safety with tiny_http)
    http_server: Arc<Mutex<Option<tiny_http::Server>>>,
    /// Current HTTP request being handled (stored for respond operation)
    current_http_request: Arc<Mutex<Option<tiny_http::Request>>>,
    /// Test results for the Test effect
    test_results: RefCell<TestResults>,
    /// SQL database connections (connection ID -> Connection)
    sql_connections: RefCell<HashMap<i64, Connection>>,
    /// Next SQL connection ID
    next_sql_conn_id: RefCell<i64>,
    /// PostgreSQL database connections (connection ID -> Client)
    pg_connections: RefCell<HashMap<i64, PgClient>>,
    /// Next PostgreSQL connection ID
    next_pg_conn_id: RefCell<i64>,
    /// Concurrent tasks: task_id -> (thunk_value, result_option, is_cancelled)
    concurrent_tasks: RefCell<HashMap<i64, (Value, Option<Value>, bool)>>,
    /// Next task ID
    next_task_id: RefCell<i64>,
    /// Channels: channel_id -> (queue, is_closed)
    channels: RefCell<HashMap<i64, (Vec<Value>, bool)>>,
    /// Next channel ID
    next_channel_id: RefCell<i64>,
}

/// Results from running tests
#[derive(Debug, Clone, Default)]
pub struct TestResults {
    pub passed: usize,
    pub failed: usize,
    pub failures: Vec<TestFailure>,
}

/// A single test failure
#[derive(Debug, Clone)]
pub struct TestFailure {
    pub message: String,
    pub expected: Option<String>,
    pub actual: Option<String>,
}

impl Interpreter {
    pub fn new() -> Self {
        let global_env = Env::new();

        // Add built-in functions
        Self::add_builtins(&global_env);

        Self {
            global_env,
            handler_stack: Vec::new(),
            evidence: HashMap::new(),
            continuations: HashMap::new(),
            trace_effects: false,
            effect_traces: Vec::new(),
            start_time: std::time::Instant::now(),
            migrations: HashMap::new(),
            builtin_state: RefCell::new(Value::Unit),
            builtin_reader: RefCell::new(Value::Unit),
            in_handler_depth: 0,
            http_server: Arc::new(Mutex::new(None)),
            current_http_request: Arc::new(Mutex::new(None)),
            test_results: RefCell::new(TestResults::default()),
            sql_connections: RefCell::new(HashMap::new()),
            next_sql_conn_id: RefCell::new(1),
            pg_connections: RefCell::new(HashMap::new()),
            next_pg_conn_id: RefCell::new(1),
            concurrent_tasks: RefCell::new(HashMap::new()),
            next_task_id: RefCell::new(1),
            channels: RefCell::new(HashMap::new()),
            next_channel_id: RefCell::new(1),
        }
    }

    /// Get the test results
    pub fn get_test_results(&self) -> TestResults {
        self.test_results.borrow().clone()
    }

    /// Reset test results for a new test run
    pub fn reset_test_results(&self) {
        *self.test_results.borrow_mut() = TestResults::default();
    }

    /// Set the initial value for the built-in State effect
    pub fn set_state(&self, value: Value) {
        *self.builtin_state.borrow_mut() = value;
    }

    /// Get the current value of the built-in State effect
    pub fn get_state(&self) -> Value {
        self.builtin_state.borrow().clone()
    }

    /// Set the value for the built-in Reader effect
    pub fn set_reader(&self, value: Value) {
        *self.builtin_reader.borrow_mut() = value;
    }

    /// Get the current value of the built-in Reader effect
    pub fn get_reader(&self) -> Value {
        self.builtin_reader.borrow().clone()
    }

    /// Enable effect tracing for debugging
    pub fn enable_tracing(&mut self) {
        self.trace_effects = true;
        self.effect_traces.clear();
        self.start_time = std::time::Instant::now();
    }

    /// Get all effect traces
    pub fn get_traces(&self) -> &[EffectTrace] {
        &self.effect_traces
    }

    /// Print effect traces in a readable format
    pub fn print_traces(&self) {
        println!("\n── EFFECT TRACE ──────────────────────────────────────");
        for trace in &self.effect_traces {
            let time_ms = trace.timestamp_us as f64 / 1000.0;
            let args_str: Vec<String> = trace.args.iter().map(|a| format!("{}", a)).collect();
            let result_str = trace
                .result
                .as_ref()
                .map(|r| format!(" → {}", r))
                .unwrap_or_default();
            println!(
                "[{:8.3}ms] {}.{}({}){}",
                time_ms,
                trace.effect,
                trace.operation,
                args_str.join(", "),
                result_str
            );
        }
        println!("──────────────────────────────────────────────────────\n");
    }

    /// Register a migration for a versioned type
    pub fn register_migration(
        &mut self,
        type_name: &str,
        from_version: u32,
        migration: StoredMigration,
    ) {
        self.migrations
            .entry(type_name.to_string())
            .or_default()
            .insert(from_version, migration);
    }

    /// Register auto-generated migrations from the typechecker
    /// These are migrations that were automatically generated for auto-migratable schema changes
    pub fn register_auto_migrations(
        &mut self,
        auto_migrations: &std::collections::HashMap<String, std::collections::HashMap<u32, Expr>>,
    ) {
        for (type_name, version_migrations) in auto_migrations {
            for (from_version, body) in version_migrations {
                // Only register if no migration already exists
                let already_has = self
                    .migrations
                    .get(type_name)
                    .map(|m| m.contains_key(from_version))
                    .unwrap_or(false);

                if !already_has {
                    let stored = StoredMigration {
                        body: body.clone(),
                        env: self.global_env.clone(),
                    };
                    self.register_migration(type_name, *from_version, stored);
                }
            }
        }
    }

    /// Create a versioned value
    pub fn create_versioned(&self, type_name: &str, version: u32, value: Value) -> Value {
        Value::Versioned {
            type_name: type_name.to_string(),
            version,
            value: Box::new(value),
        }
    }

    /// Migrate a versioned value to a target version
    pub fn migrate_value(
        &mut self,
        value: Value,
        target_version: u32,
    ) -> Result<Value, RuntimeError> {
        let (type_name, current_version, inner_value) = match value {
            Value::Versioned {
                type_name,
                version,
                value,
            } => (type_name, version, *value),
            other => return Ok(other), // Non-versioned values don't need migration
        };

        if current_version == target_version {
            return Ok(Value::Versioned {
                type_name,
                version: target_version,
                value: Box::new(inner_value),
            });
        }

        if current_version > target_version {
            return Err(RuntimeError {
                message: format!(
                    "Cannot downgrade {} from @v{} to @v{}",
                    type_name, current_version, target_version
                ),
                span: None,
            });
        }

        // Migrate step by step: v1 -> v2 -> v3 -> ... -> target
        let mut current_value = inner_value;
        let mut current_ver = current_version;

        while current_ver < target_version {
            let next_ver = current_ver + 1;

            // Look up the migration
            let migration = self
                .migrations
                .get(&type_name)
                .and_then(|m| m.get(&current_ver))
                .cloned();

            match migration {
                Some(stored_migration) => {
                    // Execute the migration
                    let migration_env = stored_migration.env.clone();
                    migration_env.define("old", current_value.clone());

                    current_value = self.eval_expr(&stored_migration.body, &migration_env)?;
                    current_ver = next_ver;
                }
                None => {
                    // No explicit migration - try auto-migration (just pass through)
                    // In a full implementation, we'd check compatibility here
                    current_ver = next_ver;
                }
            }
        }

        Ok(Value::Versioned {
            type_name,
            version: target_version,
            value: Box::new(current_value),
        })
    }

    fn add_builtins(env: &Env) {
        // Option constructors
        env.define(
            "None",
            Value::Constructor {
                name: "None".to_string(),
                fields: Vec::new(),
            },
        );
        env.define(
            "Some",
            Value::Constructor {
                name: "Some".to_string(),
                fields: Vec::new(), // Will accumulate args when called
            },
        );

        // Result constructors
        env.define(
            "Ok",
            Value::Constructor {
                name: "Ok".to_string(),
                fields: Vec::new(),
            },
        );
        env.define(
            "Err",
            Value::Constructor {
                name: "Err".to_string(),
                fields: Vec::new(),
            },
        );

        // List module (as a record with function fields)
        let list_module = Value::Record(HashMap::from([
            ("map".to_string(), Value::Builtin(BuiltinFn::ListMap)),
            ("filter".to_string(), Value::Builtin(BuiltinFn::ListFilter)),
            ("fold".to_string(), Value::Builtin(BuiltinFn::ListFold)),
            ("head".to_string(), Value::Builtin(BuiltinFn::ListHead)),
            ("tail".to_string(), Value::Builtin(BuiltinFn::ListTail)),
            ("concat".to_string(), Value::Builtin(BuiltinFn::ListConcat)),
            (
                "reverse".to_string(),
                Value::Builtin(BuiltinFn::ListReverse),
            ),
            ("length".to_string(), Value::Builtin(BuiltinFn::ListLength)),
            ("get".to_string(), Value::Builtin(BuiltinFn::ListGet)),
            ("range".to_string(), Value::Builtin(BuiltinFn::ListRange)),
            (
                "isEmpty".to_string(),
                Value::Builtin(BuiltinFn::ListIsEmpty),
            ),
            ("find".to_string(), Value::Builtin(BuiltinFn::ListFind)),
            ("any".to_string(), Value::Builtin(BuiltinFn::ListAny)),
            ("all".to_string(), Value::Builtin(BuiltinFn::ListAll)),
            ("take".to_string(), Value::Builtin(BuiltinFn::ListTake)),
            ("drop".to_string(), Value::Builtin(BuiltinFn::ListDrop)),
            (
                "forEach".to_string(),
                Value::Builtin(BuiltinFn::ListForEach),
            ),
        ]));
        env.define("List", list_module);

        // String module
        let string_module = Value::Record(HashMap::from([
            ("split".to_string(), Value::Builtin(BuiltinFn::StringSplit)),
            ("join".to_string(), Value::Builtin(BuiltinFn::StringJoin)),
            ("trim".to_string(), Value::Builtin(BuiltinFn::StringTrim)),
            (
                "contains".to_string(),
                Value::Builtin(BuiltinFn::StringContains),
            ),
            (
                "replace".to_string(),
                Value::Builtin(BuiltinFn::StringReplace),
            ),
            (
                "length".to_string(),
                Value::Builtin(BuiltinFn::StringLength),
            ),
            ("chars".to_string(), Value::Builtin(BuiltinFn::StringChars)),
            ("lines".to_string(), Value::Builtin(BuiltinFn::StringLines)),
            (
                "startsWith".to_string(),
                Value::Builtin(BuiltinFn::StringStartsWith),
            ),
            (
                "endsWith".to_string(),
                Value::Builtin(BuiltinFn::StringEndsWith),
            ),
            (
                "toUpper".to_string(),
                Value::Builtin(BuiltinFn::StringToUpper),
            ),
            (
                "toLower".to_string(),
                Value::Builtin(BuiltinFn::StringToLower),
            ),
            (
                "substring".to_string(),
                Value::Builtin(BuiltinFn::StringSubstring),
            ),
            (
                "fromChar".to_string(),
                Value::Builtin(BuiltinFn::StringFromChar),
            ),
            (
                "parseInt".to_string(),
                Value::Builtin(BuiltinFn::StringParseInt),
            ),
            (
                "parseFloat".to_string(),
                Value::Builtin(BuiltinFn::StringParseFloat),
            ),
            (
                "charAt".to_string(),
                Value::Builtin(BuiltinFn::StringCharAt),
            ),
            (
                "indexOf".to_string(),
                Value::Builtin(BuiltinFn::StringIndexOf),
            ),
            (
                "lastIndexOf".to_string(),
                Value::Builtin(BuiltinFn::StringLastIndexOf),
            ),
            (
                "repeat".to_string(),
                Value::Builtin(BuiltinFn::StringRepeat),
            ),
        ]));
        env.define("String", string_module);

        // Option module (functions, not constructors)
        let option_module = Value::Record(HashMap::from([
            ("map".to_string(), Value::Builtin(BuiltinFn::OptionMap)),
            (
                "flatMap".to_string(),
                Value::Builtin(BuiltinFn::OptionFlatMap),
            ),
            (
                "getOrElse".to_string(),
                Value::Builtin(BuiltinFn::OptionGetOrElse),
            ),
            (
                "isSome".to_string(),
                Value::Builtin(BuiltinFn::OptionIsSome),
            ),
            (
                "isNone".to_string(),
                Value::Builtin(BuiltinFn::OptionIsNone),
            ),
        ]));
        env.define("Option", option_module);

        // Result module
        let result_module = Value::Record(HashMap::from([
            ("map".to_string(), Value::Builtin(BuiltinFn::ResultMap)),
            (
                "flatMap".to_string(),
                Value::Builtin(BuiltinFn::ResultFlatMap),
            ),
            (
                "getOrElse".to_string(),
                Value::Builtin(BuiltinFn::ResultGetOrElse),
            ),
            ("isOk".to_string(), Value::Builtin(BuiltinFn::ResultIsOk)),
            ("isErr".to_string(), Value::Builtin(BuiltinFn::ResultIsErr)),
        ]));
        env.define("Result", result_module);

        // Utility functions
        env.define("print", Value::Builtin(BuiltinFn::Print));
        env.define("toString", Value::Builtin(BuiltinFn::ToString));
        env.define("typeOf", Value::Builtin(BuiltinFn::TypeOf));

        // Schema Evolution module
        let schema_module = Value::Record(HashMap::from([
            (
                "versioned".to_string(),
                Value::Builtin(BuiltinFn::Versioned),
            ),
            ("migrate".to_string(), Value::Builtin(BuiltinFn::Migrate)),
            (
                "getVersion".to_string(),
                Value::Builtin(BuiltinFn::GetVersion),
            ),
        ]));
        env.define("Schema", schema_module);

        // Math module
        let math_module = Value::Record(HashMap::from([
            ("abs".to_string(), Value::Builtin(BuiltinFn::MathAbs)),
            ("min".to_string(), Value::Builtin(BuiltinFn::MathMin)),
            ("max".to_string(), Value::Builtin(BuiltinFn::MathMax)),
            ("sqrt".to_string(), Value::Builtin(BuiltinFn::MathSqrt)),
            ("pow".to_string(), Value::Builtin(BuiltinFn::MathPow)),
            ("floor".to_string(), Value::Builtin(BuiltinFn::MathFloor)),
            ("ceil".to_string(), Value::Builtin(BuiltinFn::MathCeil)),
            ("round".to_string(), Value::Builtin(BuiltinFn::MathRound)),
        ]));
        env.define("Math", math_module);

        // JSON module
        let json_module = Value::Record(HashMap::from([
            ("parse".to_string(), Value::Builtin(BuiltinFn::JsonParse)),
            ("stringify".to_string(), Value::Builtin(BuiltinFn::JsonStringify)),
            ("prettyPrint".to_string(), Value::Builtin(BuiltinFn::JsonPrettyPrint)),
            ("get".to_string(), Value::Builtin(BuiltinFn::JsonGet)),
            ("getIndex".to_string(), Value::Builtin(BuiltinFn::JsonGetIndex)),
            ("asString".to_string(), Value::Builtin(BuiltinFn::JsonAsString)),
            ("asNumber".to_string(), Value::Builtin(BuiltinFn::JsonAsNumber)),
            ("asInt".to_string(), Value::Builtin(BuiltinFn::JsonAsInt)),
            ("asBool".to_string(), Value::Builtin(BuiltinFn::JsonAsBool)),
            ("asArray".to_string(), Value::Builtin(BuiltinFn::JsonAsArray)),
            ("isNull".to_string(), Value::Builtin(BuiltinFn::JsonIsNull)),
            ("keys".to_string(), Value::Builtin(BuiltinFn::JsonKeys)),
            ("null".to_string(), Value::Builtin(BuiltinFn::JsonNull)),
            ("bool".to_string(), Value::Builtin(BuiltinFn::JsonBool)),
            ("number".to_string(), Value::Builtin(BuiltinFn::JsonNumber)),
            ("int".to_string(), Value::Builtin(BuiltinFn::JsonInt)),
            ("string".to_string(), Value::Builtin(BuiltinFn::JsonString)),
            ("array".to_string(), Value::Builtin(BuiltinFn::JsonArray)),
            ("object".to_string(), Value::Builtin(BuiltinFn::JsonObject)),
        ]));
        env.define("Json", json_module);
    }

    /// Execute a program
    pub fn run(&mut self, program: &Program) -> Result<Value, RuntimeError> {
        let mut last_value = Value::Unit;

        for decl in &program.declarations {
            last_value = self.eval_declaration(decl)?;
        }

        Ok(last_value)
    }

    /// Execute a program with module support
    pub fn run_with_modules(
        &mut self,
        program: &Program,
        loader: &crate::modules::ModuleLoader,
    ) -> Result<Value, RuntimeError> {
        // Process imports first
        self.load_imports(&program.imports, loader)?;

        // Then run the declarations
        self.run(program)
    }

    /// Load imports into the environment
    pub fn load_imports(
        &mut self,
        imports: &[ImportDecl],
        loader: &crate::modules::ModuleLoader,
    ) -> Result<(), RuntimeError> {
        use crate::modules::ImportKind;

        let resolved = loader.resolve_imports(imports).map_err(|e| RuntimeError {
            message: e.message,
            span: None,
        })?;

        for (name, import) in resolved {
            match import.kind {
                ImportKind::Module => {
                    // Import as a module object - create a record with all exports
                    let module =
                        loader
                            .get_module(&import.module_path)
                            .ok_or_else(|| RuntimeError {
                                message: format!("Module '{}' not found", import.module_path),
                                span: None,
                            })?;

                    // Create a temporary interpreter to evaluate the module
                    // Clone the module.program to avoid borrow issues
                    let program = module.program.clone();
                    let exports = module.exports.clone();

                    let mut module_interp = Interpreter::new();
                    module_interp.run_with_modules(&program, loader)?;

                    // Collect all public values into a record
                    let mut module_record = HashMap::new();
                    for export_name in &exports {
                        if let Some(value) = module_interp.global_env.get(export_name) {
                            module_record.insert(export_name.clone(), value);
                        }
                    }

                    self.global_env.define(&name, Value::Record(module_record));
                }
                ImportKind::Direct => {
                    // Import a specific name directly
                    let module =
                        loader
                            .get_module(&import.module_path)
                            .ok_or_else(|| RuntimeError {
                                message: format!("Module '{}' not found", import.module_path),
                                span: None,
                            })?;

                    // Clone the module data to avoid borrow issues
                    let program = module.program.clone();
                    let import_name = import.name.clone();
                    let module_path = import.module_path.clone();

                    // Evaluate the module to get the value
                    let mut module_interp = Interpreter::new();
                    module_interp.run_with_modules(&program, loader)?;

                    if let Some(value) = module_interp.global_env.get(&import_name) {
                        self.global_env.define(&name, value);
                    } else {
                        return Err(RuntimeError {
                            message: format!(
                                "'{}' not found in module '{}'",
                                import_name, module_path
                            ),
                            span: None,
                        });
                    }
                }
            }
        }

        Ok(())
    }

    /// Evaluate a declaration
    fn eval_declaration(&mut self, decl: &Declaration) -> Result<Value, RuntimeError> {
        match decl {
            Declaration::Function(func) => {
                let closure = Closure {
                    params: func.params.iter().map(|p| p.name.name.clone()).collect(),
                    body: func.body.clone(),
                    env: self.global_env.clone(),
                };
                let value = Value::Function(Rc::new(closure));
                self.global_env.define(&func.name.name, value.clone());
                Ok(value)
            }

            Declaration::Let(let_decl) => {
                let value = self.eval_expr(&let_decl.value, &self.global_env.clone())?;
                self.global_env.define(&let_decl.name.name, value.clone());
                Ok(value)
            }

            Declaration::Handler(handler) => {
                let mut implementations = HashMap::new();
                for impl_ in &handler.implementations {
                    implementations.insert(impl_.op_name.name.clone(), impl_.clone());
                }

                let handler_value = HandlerValue {
                    effect: handler.effect.name.clone(),
                    implementations,
                    env: self.global_env.clone(),
                };

                let value = Value::Handler(Rc::new(handler_value));
                self.global_env.define(&handler.name.name, value.clone());
                Ok(value)
            }

            Declaration::Type(type_decl) => {
                // Register ADT constructors if this is an enum type
                if let crate::ast::TypeDef::Enum(variants) = &type_decl.definition {
                    for variant in variants {
                        let constructor = Value::Constructor {
                            name: variant.name.name.clone(),
                            fields: Vec::new(),
                        };
                        self.global_env.define(&variant.name.name, constructor);
                    }
                }

                // Register migrations for versioned types
                for migration in &type_decl.migrations {
                    let stored = StoredMigration {
                        body: migration.body.clone(),
                        env: self.global_env.clone(),
                    };
                    self.register_migration(
                        &type_decl.name.name,
                        migration.from_version.number,
                        stored,
                    );
                }

                Ok(Value::Unit)
            }

            Declaration::Effect(_) | Declaration::Trait(_) | Declaration::Impl(_) => {
                // These are compile-time only
                Ok(Value::Unit)
            }
        }
    }

    /// Evaluate an expression with tail call optimization (trampoline)
    fn eval_expr(&mut self, expr: &Expr, env: &Env) -> Result<Value, RuntimeError> {
        let mut result = self.eval_expr_inner(expr, env)?;

        // Trampoline loop for tail call optimization
        loop {
            match result {
                EvalResult::Value(v) => return Ok(v),
                EvalResult::Effect(req) => {
                    // Handle the effect
                    return self.handle_effect(req);
                }
                EvalResult::TailCall { func, args, span } => {
                    // Continue the tail call without growing the stack
                    result = self.eval_call(func, args, span)?;
                }
                EvalResult::Resume(v) => {
                    // Resume propagates up - return the value
                    return Ok(v);
                }
            }
        }
    }

    fn eval_expr_inner(&mut self, expr: &Expr, env: &Env) -> Result<EvalResult, RuntimeError> {
        self.eval_expr_tail(expr, env, false)
    }

    /// Evaluate an expression, with tail position tracking for TCO
    fn eval_expr_tail(&mut self, expr: &Expr, env: &Env, tail: bool) -> Result<EvalResult, RuntimeError> {
        match expr {
            Expr::Literal(lit) => Ok(EvalResult::Value(self.eval_literal(lit))),

            Expr::Var(ident) => match env.get(&ident.name) {
                Some(value) => Ok(EvalResult::Value(value)),
                None => Err(RuntimeError {
                    message: format!("Undefined variable: {}", ident.name),
                    span: Some(ident.span),
                }),
            },

            Expr::BinaryOp {
                op,
                left,
                right,
                span,
            } => {
                let left_val = self.eval_expr(left, env)?;
                let right_val = self.eval_expr(right, env)?;
                Ok(EvalResult::Value(
                    self.eval_binary_op(*op, left_val, right_val, *span)?,
                ))
            }

            Expr::UnaryOp { op, operand, span } => {
                let val = self.eval_expr(operand, env)?;
                Ok(EvalResult::Value(self.eval_unary_op(*op, val, *span)?))
            }

            Expr::Call { func, args, span } => {
                let func_val = self.eval_expr(func, env)?;
                let arg_vals: Vec<Value> = args
                    .iter()
                    .map(|a| self.eval_expr(a, env))
                    .collect::<Result<_, _>>()?;

                // If we're in tail position, return TailCall for trampoline
                if tail {
                    Ok(EvalResult::TailCall {
                        func: func_val,
                        args: arg_vals,
                        span: *span,
                    })
                } else {
                    self.eval_call(func_val, arg_vals, *span)
                }
            }

            Expr::EffectOp {
                effect,
                operation,
                args,
                span,
            } => {
                // Check if this is a module call instead of an effect operation
                // This includes stdlib modules (List, String, etc.) and user-imported modules
                if let Some(module_val) = env.get(&effect.name) {
                    if let Value::Record(fields) = module_val {
                        if let Some(func) = fields.get(&operation.name) {
                            let arg_vals: Vec<Value> = args
                                .iter()
                                .map(|a| self.eval_expr(a, env))
                                .collect::<Result<_, _>>()?;
                            return self.eval_call(func.clone(), arg_vals, *span);
                        } else {
                            return Err(RuntimeError {
                                message: format!(
                                    "Module '{}' has no member '{}'",
                                    effect.name, operation.name
                                ),
                                span: Some(*span),
                            });
                        }
                    }
                }

                let arg_vals: Vec<Value> = args
                    .iter()
                    .map(|a| self.eval_expr(a, env))
                    .collect::<Result<_, _>>()?;

                // Create effect request
                let request = EffectRequest {
                    effect: effect.name.clone(),
                    operation: operation.name.clone(),
                    args: arg_vals,
                    continuation: Continuation::new(),
                };

                Ok(EvalResult::Effect(request))
            }

            Expr::Field {
                object,
                field,
                span,
            } => {
                let obj_val = self.eval_expr(object, env)?;
                match obj_val {
                    Value::Record(fields) => match fields.get(&field.name) {
                        Some(v) => Ok(EvalResult::Value(v.clone())),
                        None => Err(RuntimeError {
                            message: format!("Record has no field '{}'", field.name),
                            span: Some(*span),
                        }),
                    },
                    _ => Err(RuntimeError {
                        message: format!("Cannot access field on {}", obj_val.type_name()),
                        span: Some(*span),
                    }),
                }
            }

            Expr::Lambda { params, body, .. } => {
                let closure = Closure {
                    params: params.iter().map(|p| p.name.name.clone()).collect(),
                    body: (**body).clone(),
                    env: env.clone(),
                };
                Ok(EvalResult::Value(Value::Function(Rc::new(closure))))
            }

            Expr::Let {
                name, value, body, ..
            } => {
                let val = self.eval_expr(value, env)?;
                let new_env = env.extend();
                new_env.define(&name.name, val);
                // Body of let is in tail position if the let itself is
                self.eval_expr_tail(body, &new_env, tail)
            }

            Expr::If {
                condition,
                then_branch,
                else_branch,
                span,
            } => {
                let cond_val = self.eval_expr(condition, env)?;
                match cond_val {
                    // Branches are in tail position if the if itself is
                    Value::Bool(true) => self.eval_expr_tail(then_branch, env, tail),
                    Value::Bool(false) => self.eval_expr_tail(else_branch, env, tail),
                    _ => Err(RuntimeError {
                        message: format!("If condition must be Bool, got {}", cond_val.type_name()),
                        span: Some(*span),
                    }),
                }
            }

            Expr::Match {
                scrutinee,
                arms,
                span,
            } => {
                let val = self.eval_expr(scrutinee, env)?;
                // Match arms are in tail position if the match itself is
                self.eval_match(val, arms, env, *span, tail)
            }

            Expr::Block {
                statements, result, ..
            } => {
                let block_env = env.extend();
                for stmt in statements {
                    match stmt {
                        Statement::Expr(e) => {
                            self.eval_expr(e, &block_env)?;
                        }
                        Statement::Let { name, value, .. } => {
                            let val = self.eval_expr(value, &block_env)?;
                            block_env.define(&name.name, val);
                        }
                    }
                }
                // Block result is in tail position if the block itself is
                self.eval_expr_tail(result, &block_env, tail)
            }

            Expr::Record { fields, .. } => {
                let mut record = HashMap::new();
                for (name, expr) in fields {
                    let val = self.eval_expr(expr, env)?;
                    record.insert(name.name.clone(), val);
                }
                Ok(EvalResult::Value(Value::Record(record)))
            }

            Expr::Tuple { elements, .. } => {
                let vals: Vec<Value> = elements
                    .iter()
                    .map(|e| self.eval_expr(e, env))
                    .collect::<Result<_, _>>()?;
                Ok(EvalResult::Value(Value::Tuple(vals)))
            }

            Expr::List { elements, .. } => {
                let vals: Vec<Value> = elements
                    .iter()
                    .map(|e| self.eval_expr(e, env))
                    .collect::<Result<_, _>>()?;
                Ok(EvalResult::Value(Value::List(vals)))
            }

            Expr::Run {
                expr,
                handlers,
                span,
            } => self.eval_run(expr, handlers, env, *span),

            Expr::Resume { value, span } => {
                if self.in_handler_depth > 0 {
                    // We're inside a handler body - evaluate the value and return Resume
                    let val = self.eval_expr(value, env)?;
                    Ok(EvalResult::Resume(val))
                } else {
                    Err(RuntimeError {
                        message: "Resume called outside of handler".to_string(),
                        span: Some(*span),
                    })
                }
            }
        }
    }

    fn eval_literal(&self, lit: &Literal) -> Value {
        match &lit.kind {
            LiteralKind::Int(n) => Value::Int(*n),
            LiteralKind::Float(f) => Value::Float(*f),
            LiteralKind::String(s) => Value::String(s.clone()),
            LiteralKind::Char(c) => Value::Char(*c),
            LiteralKind::Bool(b) => Value::Bool(*b),
            LiteralKind::Unit => Value::Unit,
        }
    }

    fn eval_binary_op(
        &mut self,
        op: BinaryOp,
        left: Value,
        right: Value,
        span: Span,
    ) -> Result<Value, RuntimeError> {
        match op {
            BinaryOp::Add => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a + b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)),
                (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot add {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Sub => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a - b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a - b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot subtract {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Mul => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a * b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a * b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot multiply {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Div => match (left, right) {
                (Value::Int(a), Value::Int(b)) => {
                    if b == 0 {
                        Err(RuntimeError {
                            message: "Division by zero".to_string(),
                            span: Some(span),
                        })
                    } else {
                        Ok(Value::Int(a / b))
                    }
                }
                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a / b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot divide {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Mod => match (left, right) {
                (Value::Int(a), Value::Int(b)) => {
                    if b == 0 {
                        Err(RuntimeError {
                            message: "Modulo by zero".to_string(),
                            span: Some(span),
                        })
                    } else {
                        Ok(Value::Int(a % b))
                    }
                }
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot modulo {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Eq => Ok(Value::Bool(self.values_equal(&left, &right))),
            BinaryOp::Ne => Ok(Value::Bool(!self.values_equal(&left, &right))),
            BinaryOp::Lt => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a < b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a < b)),
                (Value::String(a), Value::String(b)) => Ok(Value::Bool(a < b)),
                (Value::Char(a), Value::Char(b)) => Ok(Value::Bool(a < b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot compare {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Le => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a <= b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a <= b)),
                (Value::String(a), Value::String(b)) => Ok(Value::Bool(a <= b)),
                (Value::Char(a), Value::Char(b)) => Ok(Value::Bool(a <= b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot compare {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Gt => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a > b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a > b)),
                (Value::String(a), Value::String(b)) => Ok(Value::Bool(a > b)),
                (Value::Char(a), Value::Char(b)) => Ok(Value::Bool(a > b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot compare {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Ge => match (left, right) {
                (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a >= b)),
                (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a >= b)),
                (Value::String(a), Value::String(b)) => Ok(Value::Bool(a >= b)),
                (Value::Char(a), Value::Char(b)) => Ok(Value::Bool(a >= b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot compare {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::And => match (left, right) {
                (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a && b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot 'and' {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Or => match (left, right) {
                (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a || b)),
                (l, r) => Err(RuntimeError {
                    message: format!("Cannot 'or' {} and {}", l.type_name(), r.type_name()),
                    span: Some(span),
                }),
            },
            BinaryOp::Pipe => {
                // a |> f means f(a)
                self.eval_call_to_value(right, vec![left], span)
            }
        }
    }

    fn eval_unary_op(&self, op: UnaryOp, val: Value, span: Span) -> Result<Value, RuntimeError> {
        match op {
            UnaryOp::Neg => match val {
                Value::Int(n) => Ok(Value::Int(-n)),
                Value::Float(f) => Ok(Value::Float(-f)),
                v => Err(RuntimeError {
                    message: format!("Cannot negate {}", v.type_name()),
                    span: Some(span),
                }),
            },
            UnaryOp::Not => match val {
                Value::Bool(b) => Ok(Value::Bool(!b)),
                v => Err(RuntimeError {
                    message: format!("Cannot negate {}", v.type_name()),
                    span: Some(span),
                }),
            },
        }
    }

    fn eval_call(
        &mut self,
        func: Value,
        args: Vec<Value>,
        span: Span,
    ) -> Result<EvalResult, RuntimeError> {
        match func {
            Value::Function(closure) => {
                if closure.params.len() != args.len() {
                    return Err(RuntimeError {
                        message: format!(
                            "Function expects {} arguments, got {}",
                            closure.params.len(),
                            args.len()
                        ),
                        span: Some(span),
                    });
                }

                let call_env = closure.env.extend();
                for (param, arg) in closure.params.iter().zip(args) {
                    call_env.define(param, arg);
                }

                // Evaluate body in tail position for TCO
                self.eval_expr_tail(&closure.body, &call_env, true)
            }
            Value::Constructor { name, fields } => {
                // Constructor application
                let mut new_fields = fields;
                new_fields.extend(args);
                Ok(EvalResult::Value(Value::Constructor {
                    name,
                    fields: new_fields,
                }))
            }
            Value::Builtin(builtin) => self.eval_builtin(builtin, args, span),
            v => Err(RuntimeError {
                message: format!("Cannot call {}", v.type_name()),
                span: Some(span),
            }),
        }
    }

    /// Fully evaluate a call, handling any tail calls via trampoline.
    /// Used by builtins that need to call user functions and get a value back.
    fn eval_call_to_value(
        &mut self,
        func: Value,
        args: Vec<Value>,
        span: Span,
    ) -> Result<Value, RuntimeError> {
        let mut result = self.eval_call(func, args, span)?;
        loop {
            match result {
                EvalResult::Value(v) => return Ok(v),
                EvalResult::Effect(req) => {
                    // Handle the effect and continue
                    let handled = self.handle_effect(req)?;
                    return Ok(handled);
                }
                EvalResult::TailCall { func, args, span } => {
                    result = self.eval_call(func, args, span)?;
                }
                EvalResult::Resume(v) => return Ok(v),
            }
        }
    }

    fn eval_builtin(
        &mut self,
        builtin: BuiltinFn,
        args: Vec<Value>,
        span: Span,
    ) -> Result<EvalResult, RuntimeError> {
        let err = |msg: &str| RuntimeError {
            message: msg.to_string(),
            span: Some(span),
        };

        match builtin {
            // List operations
            BuiltinFn::ListMap => {
                let (list, func) =
                    Self::expect_args_2::<Vec<Value>, Value>(&args, "List.map", span)?;
                let mut result = Vec::with_capacity(list.len());
                for item in list {
                    let v = self.eval_call_to_value(func.clone(), vec![item], span)?;
                    result.push(v);
                }
                Ok(EvalResult::Value(Value::List(result)))
            }

            BuiltinFn::ListFilter => {
                let (list, func) =
                    Self::expect_args_2::<Vec<Value>, Value>(&args, "List.filter", span)?;
                let mut result = Vec::new();
                for item in list {
                    let v = self.eval_call_to_value(func.clone(), vec![item.clone()], span)?;
                    match v {
                        Value::Bool(true) => result.push(item),
                        Value::Bool(false) => {}
                        _ => {
                            return Err(err(&format!(
                                "List.filter predicate must return Bool, got {}",
                                v.type_name()
                            )))
                        }
                    }
                }
                Ok(EvalResult::Value(Value::List(result)))
            }

            BuiltinFn::ListFold => {
                // List.fold(list, initial, fn(acc, item) => ...)
                if args.len() != 3 {
                    return Err(err(
                        "List.fold requires 3 arguments: list, initial, reducer",
                    ));
                }
                let list = match &args[0] {
                    Value::List(l) => l.clone(),
                    v => {
                        return Err(err(&format!(
                            "List.fold expects List as first argument, got {}",
                            v.type_name()
                        )))
                    }
                };
                let mut acc = args[1].clone();
                let func = args[2].clone();

                for item in list {
                    acc = self.eval_call_to_value(func.clone(), vec![acc, item], span)?;
                }
                Ok(EvalResult::Value(acc))
            }

            BuiltinFn::ListHead => {
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "List.head", span)?;
                match list.first() {
                    Some(v) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![v.clone()],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::ListTail => {
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "List.tail", span)?;
                if list.is_empty() {
                    Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    }))
                } else {
                    Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::List(list[1..].to_vec())],
                    }))
                }
            }

            BuiltinFn::ListConcat => {
                let (list1, list2) =
                    Self::expect_args_2::<Vec<Value>, Vec<Value>>(&args, "List.concat", span)?;
                let mut result = list1;
                result.extend(list2);
                Ok(EvalResult::Value(Value::List(result)))
            }

            BuiltinFn::ListReverse => {
                let mut list = Self::expect_arg_1::<Vec<Value>>(&args, "List.reverse", span)?;
                list.reverse();
                Ok(EvalResult::Value(Value::List(list)))
            }

            BuiltinFn::ListLength => {
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "List.length", span)?;
                Ok(EvalResult::Value(Value::Int(list.len() as i64)))
            }

            BuiltinFn::ListGet => {
                let (list, idx) = Self::expect_args_2::<Vec<Value>, i64>(&args, "List.get", span)?;
                if idx < 0 || idx as usize >= list.len() {
                    Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    }))
                } else {
                    Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![list[idx as usize].clone()],
                    }))
                }
            }

            BuiltinFn::ListRange => {
                let (start, end) = Self::expect_args_2::<i64, i64>(&args, "List.range", span)?;
                let list: Vec<Value> = (start..end).map(Value::Int).collect();
                Ok(EvalResult::Value(Value::List(list)))
            }

            // String operations
            BuiltinFn::StringSplit => {
                let (s, delim) =
                    Self::expect_args_2::<String, String>(&args, "String.split", span)?;
                let parts: Vec<Value> = s
                    .split(&delim)
                    .map(|p| Value::String(p.to_string()))
                    .collect();
                Ok(EvalResult::Value(Value::List(parts)))
            }

            BuiltinFn::StringJoin => {
                let (list, sep) =
                    Self::expect_args_2::<Vec<Value>, String>(&args, "String.join", span)?;
                let strings: Result<Vec<String>, _> = list
                    .iter()
                    .map(|v| match v {
                        Value::String(s) => Ok(s.clone()),
                        _ => Err(err("String.join requires list of strings")),
                    })
                    .collect();
                Ok(EvalResult::Value(Value::String(strings?.join(&sep))))
            }

            BuiltinFn::StringTrim => {
                let s = Self::expect_arg_1::<String>(&args, "String.trim", span)?;
                Ok(EvalResult::Value(Value::String(s.trim().to_string())))
            }

            BuiltinFn::StringContains => {
                let (s, needle) =
                    Self::expect_args_2::<String, String>(&args, "String.contains", span)?;
                Ok(EvalResult::Value(Value::Bool(s.contains(&needle))))
            }

            BuiltinFn::StringReplace => {
                if args.len() != 3 {
                    return Err(err("String.replace requires 3 arguments: string, from, to"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => {
                        return Err(err(&format!(
                            "String.replace expects String, got {}",
                            v.type_name()
                        )))
                    }
                };
                let from = match &args[1] {
                    Value::String(s) => s.clone(),
                    v => {
                        return Err(err(&format!(
                            "String.replace expects String, got {}",
                            v.type_name()
                        )))
                    }
                };
                let to = match &args[2] {
                    Value::String(s) => s.clone(),
                    v => {
                        return Err(err(&format!(
                            "String.replace expects String, got {}",
                            v.type_name()
                        )))
                    }
                };
                Ok(EvalResult::Value(Value::String(s.replace(&from, &to))))
            }

            BuiltinFn::StringLength => {
                let s = Self::expect_arg_1::<String>(&args, "String.length", span)?;
                Ok(EvalResult::Value(Value::Int(s.len() as i64)))
            }

            BuiltinFn::StringChars => {
                let s = Self::expect_arg_1::<String>(&args, "String.chars", span)?;
                let chars: Vec<Value> = s.chars().map(Value::Char).collect();
                Ok(EvalResult::Value(Value::List(chars)))
            }

            BuiltinFn::StringLines => {
                let s = Self::expect_arg_1::<String>(&args, "String.lines", span)?;
                let lines: Vec<Value> = s.lines().map(|l| Value::String(l.to_string())).collect();
                Ok(EvalResult::Value(Value::List(lines)))
            }

            BuiltinFn::StringParseInt => {
                let s = Self::expect_arg_1::<String>(&args, "String.parseInt", span)?;
                let trimmed = s.trim();
                match trimmed.parse::<i64>() {
                    Ok(n) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Int(n)],
                    })),
                    Err(_) => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::StringParseFloat => {
                let s = Self::expect_arg_1::<String>(&args, "String.parseFloat", span)?;
                let trimmed = s.trim();
                match trimmed.parse::<f64>() {
                    Ok(f) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Float(f)],
                    })),
                    Err(_) => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            // Option operations
            BuiltinFn::OptionMap => {
                let (opt, func) = Self::expect_args_2::<Value, Value>(&args, "Option.map", span)?;
                match opt {
                    Value::Constructor { name, fields } if name == "Some" && !fields.is_empty() => {
                        let v = self.eval_call_to_value(func, vec![fields[0].clone()], span)?;
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Some".to_string(),
                            fields: vec![v],
                        }))
                    }
                    Value::Constructor { name, .. } if name == "None" => {
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "None".to_string(),
                            fields: vec![],
                        }))
                    }
                    v => Err(err(&format!(
                        "Option.map expects Option, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::OptionFlatMap => {
                let (opt, func) =
                    Self::expect_args_2::<Value, Value>(&args, "Option.flatMap", span)?;
                match opt {
                    Value::Constructor { name, fields } if name == "Some" && !fields.is_empty() => {
                        let v = self.eval_call_to_value(func, vec![fields[0].clone()], span)?;
                        Ok(EvalResult::Value(v))
                    }
                    Value::Constructor { name, .. } if name == "None" => {
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "None".to_string(),
                            fields: vec![],
                        }))
                    }
                    v => Err(err(&format!(
                        "Option.flatMap expects Option, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::OptionGetOrElse => {
                let (opt, default) =
                    Self::expect_args_2::<Value, Value>(&args, "Option.getOrElse", span)?;
                match opt {
                    Value::Constructor { name, fields } if name == "Some" && !fields.is_empty() => {
                        Ok(EvalResult::Value(fields[0].clone()))
                    }
                    Value::Constructor { name, .. } if name == "None" => {
                        Ok(EvalResult::Value(default))
                    }
                    v => Err(err(&format!(
                        "Option.getOrElse expects Option, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::OptionIsSome => {
                let opt = Self::expect_arg_1::<Value>(&args, "Option.isSome", span)?;
                match opt {
                    Value::Constructor { name, .. } if name == "Some" => {
                        Ok(EvalResult::Value(Value::Bool(true)))
                    }
                    Value::Constructor { name, .. } if name == "None" => {
                        Ok(EvalResult::Value(Value::Bool(false)))
                    }
                    v => Err(err(&format!(
                        "Option.isSome expects Option, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::OptionIsNone => {
                let opt = Self::expect_arg_1::<Value>(&args, "Option.isNone", span)?;
                match opt {
                    Value::Constructor { name, .. } if name == "None" => {
                        Ok(EvalResult::Value(Value::Bool(true)))
                    }
                    Value::Constructor { name, .. } if name == "Some" => {
                        Ok(EvalResult::Value(Value::Bool(false)))
                    }
                    v => Err(err(&format!(
                        "Option.isNone expects Option, got {}",
                        v.type_name()
                    ))),
                }
            }

            // Result operations
            BuiltinFn::ResultMap => {
                let (res, func) = Self::expect_args_2::<Value, Value>(&args, "Result.map", span)?;
                match res {
                    Value::Constructor { name, fields } if name == "Ok" && !fields.is_empty() => {
                        let v = self.eval_call_to_value(func, vec![fields[0].clone()], span)?;
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Ok".to_string(),
                            fields: vec![v],
                        }))
                    }
                    Value::Constructor { name, fields } if name == "Err" => {
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Err".to_string(),
                            fields,
                        }))
                    }
                    v => Err(err(&format!(
                        "Result.map expects Result, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::ResultFlatMap => {
                let (res, func) =
                    Self::expect_args_2::<Value, Value>(&args, "Result.flatMap", span)?;
                match res {
                    Value::Constructor { name, fields } if name == "Ok" && !fields.is_empty() => {
                        let v = self.eval_call_to_value(func, vec![fields[0].clone()], span)?;
                        Ok(EvalResult::Value(v))
                    }
                    Value::Constructor { name, fields } if name == "Err" => {
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Err".to_string(),
                            fields,
                        }))
                    }
                    v => Err(err(&format!(
                        "Result.flatMap expects Result, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::ResultGetOrElse => {
                let (res, default) =
                    Self::expect_args_2::<Value, Value>(&args, "Result.getOrElse", span)?;
                match res {
                    Value::Constructor { name, fields } if name == "Ok" && !fields.is_empty() => {
                        Ok(EvalResult::Value(fields[0].clone()))
                    }
                    Value::Constructor { name, .. } if name == "Err" => {
                        Ok(EvalResult::Value(default))
                    }
                    v => Err(err(&format!(
                        "Result.getOrElse expects Result, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::ResultIsOk => {
                let res = Self::expect_arg_1::<Value>(&args, "Result.isOk", span)?;
                match res {
                    Value::Constructor { name, .. } if name == "Ok" => {
                        Ok(EvalResult::Value(Value::Bool(true)))
                    }
                    Value::Constructor { name, .. } if name == "Err" => {
                        Ok(EvalResult::Value(Value::Bool(false)))
                    }
                    v => Err(err(&format!(
                        "Result.isOk expects Result, got {}",
                        v.type_name()
                    ))),
                }
            }

            BuiltinFn::ResultIsErr => {
                let res = Self::expect_arg_1::<Value>(&args, "Result.isErr", span)?;
                match res {
                    Value::Constructor { name, .. } if name == "Err" => {
                        Ok(EvalResult::Value(Value::Bool(true)))
                    }
                    Value::Constructor { name, .. } if name == "Ok" => {
                        Ok(EvalResult::Value(Value::Bool(false)))
                    }
                    v => Err(err(&format!(
                        "Result.isErr expects Result, got {}",
                        v.type_name()
                    ))),
                }
            }

            // Utility functions
            BuiltinFn::Print => {
                for arg in &args {
                    match arg {
                        Value::String(s) => print!("{}", s),
                        v => print!("{}", v),
                    }
                }
                println!();
                Ok(EvalResult::Value(Value::Unit))
            }

            BuiltinFn::ToString => {
                if args.len() != 1 {
                    return Err(err("toString requires 1 argument"));
                }
                // For strings, return the string itself (no quotes)
                // For other values, use Display formatting
                let result = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => format!("{}", v),
                };
                Ok(EvalResult::Value(Value::String(result)))
            }

            BuiltinFn::TypeOf => {
                if args.len() != 1 {
                    return Err(err("typeOf requires 1 argument"));
                }
                Ok(EvalResult::Value(Value::String(
                    args[0].type_name().to_string(),
                )))
            }

            // Schema Evolution
            BuiltinFn::Versioned => {
                // versioned(typeName: String, version: Int, value: Any) -> Versioned
                if args.len() != 3 {
                    return Err(err("Schema.versioned requires 3 arguments: typeName, version, value"));
                }
                let type_name = match &args[0] {
                    Value::String(s) => s.clone(),
                    _ => return Err(err("Schema.versioned: first argument must be a String")),
                };
                let version = match &args[1] {
                    Value::Int(n) => *n as u32,
                    _ => return Err(err("Schema.versioned: second argument must be an Int")),
                };
                Ok(EvalResult::Value(Value::Versioned {
                    type_name,
                    version,
                    value: Box::new(args[2].clone()),
                }))
            }

            BuiltinFn::Migrate => {
                // migrate(value: Versioned, targetVersion: Int) -> Versioned
                if args.len() != 2 {
                    return Err(err("Schema.migrate requires 2 arguments: value, targetVersion"));
                }
                let target = match &args[1] {
                    Value::Int(n) => *n as u32,
                    _ => return Err(err("Schema.migrate: second argument must be an Int")),
                };
                // Use migrate_value which executes registered migrations
                let migrated = self.migrate_value(args[0].clone(), target)?;
                Ok(EvalResult::Value(migrated))
            }

            BuiltinFn::GetVersion => {
                // getVersion(value: Versioned) -> Int
                if args.len() != 1 {
                    return Err(err("Schema.getVersion requires 1 argument"));
                }
                match &args[0] {
                    Value::Versioned { version, .. } => {
                        Ok(EvalResult::Value(Value::Int(*version as i64)))
                    }
                    _ => Err(err("Schema.getVersion: argument must be a Versioned value")),
                }
            }

            // Math operations
            BuiltinFn::MathAbs => {
                if args.len() != 1 {
                    return Err(err("Math.abs requires 1 argument"));
                }
                match &args[0] {
                    Value::Int(n) => Ok(EvalResult::Value(Value::Int(n.abs()))),
                    Value::Float(n) => Ok(EvalResult::Value(Value::Float(n.abs()))),
                    v => Err(err(&format!("Math.abs expects number, got {}", v.type_name()))),
                }
            }

            BuiltinFn::MathMin => {
                let (a, b) = Self::expect_args_2::<i64, i64>(&args, "Math.min", span)
                    .or_else(|_| {
                        // Try floats
                        if args.len() == 2 {
                            match (&args[0], &args[1]) {
                                (Value::Float(a), Value::Float(b)) => {
                                    return Ok((0i64, 0i64)); // Placeholder - we'll handle below
                                }
                                _ => {}
                            }
                        }
                        Err(err("Math.min requires 2 number arguments"))
                    })?;
                // Check if they were floats
                match (&args[0], &args[1]) {
                    (Value::Float(a), Value::Float(b)) => {
                        Ok(EvalResult::Value(Value::Float(a.min(*b))))
                    }
                    (Value::Int(a), Value::Int(b)) => {
                        Ok(EvalResult::Value(Value::Int((*a).min(*b))))
                    }
                    _ => Err(err("Math.min requires 2 number arguments")),
                }
            }

            BuiltinFn::MathMax => {
                match (&args[0], &args[1]) {
                    (Value::Float(a), Value::Float(b)) => {
                        Ok(EvalResult::Value(Value::Float(a.max(*b))))
                    }
                    (Value::Int(a), Value::Int(b)) => {
                        Ok(EvalResult::Value(Value::Int((*a).max(*b))))
                    }
                    _ => Err(err("Math.max requires 2 number arguments")),
                }
            }

            BuiltinFn::MathSqrt => {
                if args.len() != 1 {
                    return Err(err("Math.sqrt requires 1 argument"));
                }
                match &args[0] {
                    Value::Int(n) => Ok(EvalResult::Value(Value::Float((*n as f64).sqrt()))),
                    Value::Float(n) => Ok(EvalResult::Value(Value::Float(n.sqrt()))),
                    v => Err(err(&format!("Math.sqrt expects number, got {}", v.type_name()))),
                }
            }

            BuiltinFn::MathPow => {
                if args.len() != 2 {
                    return Err(err("Math.pow requires 2 arguments: base, exponent"));
                }
                match (&args[0], &args[1]) {
                    (Value::Int(base), Value::Int(exp)) => {
                        if *exp >= 0 {
                            Ok(EvalResult::Value(Value::Int(base.pow(*exp as u32))))
                        } else {
                            Ok(EvalResult::Value(Value::Float((*base as f64).powi(*exp as i32))))
                        }
                    }
                    (Value::Float(base), Value::Int(exp)) => {
                        Ok(EvalResult::Value(Value::Float(base.powi(*exp as i32))))
                    }
                    (Value::Float(base), Value::Float(exp)) => {
                        Ok(EvalResult::Value(Value::Float(base.powf(*exp))))
                    }
                    (Value::Int(base), Value::Float(exp)) => {
                        Ok(EvalResult::Value(Value::Float((*base as f64).powf(*exp))))
                    }
                    _ => Err(err("Math.pow requires number arguments")),
                }
            }

            BuiltinFn::MathFloor => {
                if args.len() != 1 {
                    return Err(err("Math.floor requires 1 argument"));
                }
                match &args[0] {
                    Value::Float(n) => Ok(EvalResult::Value(Value::Int(n.floor() as i64))),
                    Value::Int(n) => Ok(EvalResult::Value(Value::Int(*n))),
                    v => Err(err(&format!("Math.floor expects number, got {}", v.type_name()))),
                }
            }

            BuiltinFn::MathCeil => {
                if args.len() != 1 {
                    return Err(err("Math.ceil requires 1 argument"));
                }
                match &args[0] {
                    Value::Float(n) => Ok(EvalResult::Value(Value::Int(n.ceil() as i64))),
                    Value::Int(n) => Ok(EvalResult::Value(Value::Int(*n))),
                    v => Err(err(&format!("Math.ceil expects number, got {}", v.type_name()))),
                }
            }

            BuiltinFn::MathRound => {
                if args.len() != 1 {
                    return Err(err("Math.round requires 1 argument"));
                }
                match &args[0] {
                    Value::Float(n) => Ok(EvalResult::Value(Value::Int(n.round() as i64))),
                    Value::Int(n) => Ok(EvalResult::Value(Value::Int(*n))),
                    v => Err(err(&format!("Math.round expects number, got {}", v.type_name()))),
                }
            }

            // Additional List operations
            BuiltinFn::ListIsEmpty => {
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "List.isEmpty", span)?;
                Ok(EvalResult::Value(Value::Bool(list.is_empty())))
            }

            BuiltinFn::ListFind => {
                let (list, func) = Self::expect_args_2::<Vec<Value>, Value>(&args, "List.find", span)?;
                for item in list {
                    let v = self.eval_call_to_value(func.clone(), vec![item.clone()], span)?;
                    match v {
                        Value::Bool(true) => {
                            return Ok(EvalResult::Value(Value::Constructor {
                                name: "Some".to_string(),
                                fields: vec![item],
                            }));
                        }
                        Value::Bool(false) => {}
                        _ => return Err(err("List.find predicate must return Bool")),
                    }
                }
                Ok(EvalResult::Value(Value::Constructor {
                    name: "None".to_string(),
                    fields: vec![],
                }))
            }

            BuiltinFn::ListAny => {
                let (list, func) = Self::expect_args_2::<Vec<Value>, Value>(&args, "List.any", span)?;
                for item in list {
                    let v = self.eval_call_to_value(func.clone(), vec![item], span)?;
                    match v {
                        Value::Bool(true) => return Ok(EvalResult::Value(Value::Bool(true))),
                        Value::Bool(false) => {}
                        _ => return Err(err("List.any predicate must return Bool")),
                    }
                }
                Ok(EvalResult::Value(Value::Bool(false)))
            }

            BuiltinFn::ListAll => {
                let (list, func) = Self::expect_args_2::<Vec<Value>, Value>(&args, "List.all", span)?;
                for item in list {
                    let v = self.eval_call_to_value(func.clone(), vec![item], span)?;
                    match v {
                        Value::Bool(false) => return Ok(EvalResult::Value(Value::Bool(false))),
                        Value::Bool(true) => {}
                        _ => return Err(err("List.all predicate must return Bool")),
                    }
                }
                Ok(EvalResult::Value(Value::Bool(true)))
            }

            BuiltinFn::ListTake => {
                let (list, n) = Self::expect_args_2::<Vec<Value>, i64>(&args, "List.take", span)?;
                let n = n.max(0) as usize;
                let result: Vec<Value> = list.into_iter().take(n).collect();
                Ok(EvalResult::Value(Value::List(result)))
            }

            BuiltinFn::ListDrop => {
                let (list, n) = Self::expect_args_2::<Vec<Value>, i64>(&args, "List.drop", span)?;
                let n = n.max(0) as usize;
                let result: Vec<Value> = list.into_iter().skip(n).collect();
                Ok(EvalResult::Value(Value::List(result)))
            }

            BuiltinFn::ListForEach => {
                // List.forEach(list, fn(item) => { effectful code })
                // Unlike map, forEach doesn't collect results - it just runs effects
                let (list, func) =
                    Self::expect_args_2::<Vec<Value>, Value>(&args, "List.forEach", span)?;
                for item in list {
                    // Call the function for each item, ignoring the result
                    self.eval_call_to_value(func.clone(), vec![item], span)?;
                }
                Ok(EvalResult::Value(Value::Unit))
            }

            // Additional String operations
            BuiltinFn::StringStartsWith => {
                let (s, prefix) = Self::expect_args_2::<String, String>(&args, "String.startsWith", span)?;
                Ok(EvalResult::Value(Value::Bool(s.starts_with(&prefix))))
            }

            BuiltinFn::StringEndsWith => {
                let (s, suffix) = Self::expect_args_2::<String, String>(&args, "String.endsWith", span)?;
                Ok(EvalResult::Value(Value::Bool(s.ends_with(&suffix))))
            }

            BuiltinFn::StringToUpper => {
                let s = Self::expect_arg_1::<String>(&args, "String.toUpper", span)?;
                Ok(EvalResult::Value(Value::String(s.to_uppercase())))
            }

            BuiltinFn::StringToLower => {
                let s = Self::expect_arg_1::<String>(&args, "String.toLower", span)?;
                Ok(EvalResult::Value(Value::String(s.to_lowercase())))
            }

            BuiltinFn::StringSubstring => {
                // String.substring(s, start, end) - end is exclusive
                if args.len() != 3 {
                    return Err(err("String.substring requires 3 arguments: string, start, end"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.substring expects String, got {}", v.type_name()))),
                };
                let start = match &args[1] {
                    Value::Int(n) => (*n).max(0) as usize,
                    v => return Err(err(&format!("String.substring expects Int for start, got {}", v.type_name()))),
                };
                let end = match &args[2] {
                    Value::Int(n) => (*n).max(0) as usize,
                    v => return Err(err(&format!("String.substring expects Int for end, got {}", v.type_name()))),
                };
                let chars: Vec<char> = s.chars().collect();
                let end = end.min(chars.len());
                let start = start.min(end);
                let result: String = chars[start..end].iter().collect();
                Ok(EvalResult::Value(Value::String(result)))
            }

            BuiltinFn::StringFromChar => {
                if args.len() != 1 {
                    return Err(err("String.fromChar requires 1 argument: char"));
                }
                let c = match &args[0] {
                    Value::Char(c) => *c,
                    v => return Err(err(&format!("String.fromChar expects Char, got {}", v.type_name()))),
                };
                Ok(EvalResult::Value(Value::String(c.to_string())))
            }

            BuiltinFn::StringCharAt => {
                if args.len() != 2 {
                    return Err(err("String.charAt requires 2 arguments: string, index"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.charAt expects String, got {}", v.type_name()))),
                };
                let idx = match &args[1] {
                    Value::Int(n) => *n as usize,
                    v => return Err(err(&format!("String.charAt expects Int for index, got {}", v.type_name()))),
                };
                let chars: Vec<char> = s.chars().collect();
                if idx < chars.len() {
                    Ok(EvalResult::Value(Value::String(chars[idx].to_string())))
                } else {
                    Ok(EvalResult::Value(Value::String(String::new())))
                }
            }

            BuiltinFn::StringIndexOf => {
                if args.len() != 2 {
                    return Err(err("String.indexOf requires 2 arguments: string, substring"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.indexOf expects String, got {}", v.type_name()))),
                };
                let sub = match &args[1] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.indexOf expects String for substring, got {}", v.type_name()))),
                };
                match s.find(&sub) {
                    Some(idx) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Int(idx as i64)],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::StringLastIndexOf => {
                if args.len() != 2 {
                    return Err(err("String.lastIndexOf requires 2 arguments: string, substring"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.lastIndexOf expects String, got {}", v.type_name()))),
                };
                let sub = match &args[1] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.lastIndexOf expects String for substring, got {}", v.type_name()))),
                };
                match s.rfind(&sub) {
                    Some(idx) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Int(idx as i64)],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::StringRepeat => {
                if args.len() != 2 {
                    return Err(err("String.repeat requires 2 arguments: string, count"));
                }
                let s = match &args[0] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("String.repeat expects String, got {}", v.type_name()))),
                };
                let count = match &args[1] {
                    Value::Int(n) => (*n).max(0) as usize,
                    v => return Err(err(&format!("String.repeat expects Int for count, got {}", v.type_name()))),
                };
                Ok(EvalResult::Value(Value::String(s.repeat(count))))
            }

            // JSON operations
            BuiltinFn::JsonParse => {
                let s = Self::expect_arg_1::<String>(&args, "Json.parse", span)?;
                match serde_json::from_str::<serde_json::Value>(&s) {
                    Ok(json) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Ok".to_string(),
                        fields: vec![Value::Json(json)],
                    })),
                    Err(e) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Err".to_string(),
                        fields: vec![Value::String(e.to_string())],
                    })),
                }
            }

            BuiltinFn::JsonStringify => {
                let json = match &args[0] {
                    Value::Json(j) => j.clone(),
                    v => return Err(err(&format!("Json.stringify expects Json, got {}", v.type_name()))),
                };
                Ok(EvalResult::Value(Value::String(json.to_string())))
            }

            BuiltinFn::JsonPrettyPrint => {
                let json = match &args[0] {
                    Value::Json(j) => j.clone(),
                    v => return Err(err(&format!("Json.prettyPrint expects Json, got {}", v.type_name()))),
                };
                match serde_json::to_string_pretty(&json) {
                    Ok(s) => Ok(EvalResult::Value(Value::String(s))),
                    Err(e) => Err(err(&format!("Json.prettyPrint error: {}", e))),
                }
            }

            BuiltinFn::JsonGet => {
                // Json.get(json, key) -> Option<Json>
                if args.len() != 2 {
                    return Err(err("Json.get requires 2 arguments: json, key"));
                }
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.get expects Json, got {}", v.type_name()))),
                };
                let key = match &args[1] {
                    Value::String(s) => s.clone(),
                    v => return Err(err(&format!("Json.get expects String key, got {}", v.type_name()))),
                };
                match json.get(&key) {
                    Some(v) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Json(v.clone())],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonGetIndex => {
                // Json.getIndex(json, index) -> Option<Json>
                if args.len() != 2 {
                    return Err(err("Json.getIndex requires 2 arguments: json, index"));
                }
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.getIndex expects Json, got {}", v.type_name()))),
                };
                let idx = match &args[1] {
                    Value::Int(n) => *n as usize,
                    v => return Err(err(&format!("Json.getIndex expects Int index, got {}", v.type_name()))),
                };
                match json.get(idx) {
                    Some(v) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Json(v.clone())],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonAsString => {
                // Json.asString(json) -> Option<String>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.asString expects Json, got {}", v.type_name()))),
                };
                match json.as_str() {
                    Some(s) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::String(s.to_string())],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonAsNumber => {
                // Json.asNumber(json) -> Option<Float>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.asNumber expects Json, got {}", v.type_name()))),
                };
                match json.as_f64() {
                    Some(n) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Float(n)],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonAsInt => {
                // Json.asInt(json) -> Option<Int>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.asInt expects Json, got {}", v.type_name()))),
                };
                match json.as_i64() {
                    Some(n) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Int(n)],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonAsBool => {
                // Json.asBool(json) -> Option<Bool>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.asBool expects Json, got {}", v.type_name()))),
                };
                match json.as_bool() {
                    Some(b) => Ok(EvalResult::Value(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::Bool(b)],
                    })),
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonAsArray => {
                // Json.asArray(json) -> Option<List<Json>>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.asArray expects Json, got {}", v.type_name()))),
                };
                match json.as_array() {
                    Some(arr) => {
                        let items: Vec<Value> = arr.iter().map(|v| Value::Json(v.clone())).collect();
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Some".to_string(),
                            fields: vec![Value::List(items)],
                        }))
                    }
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            BuiltinFn::JsonIsNull => {
                // Json.isNull(json) -> Bool
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.isNull expects Json, got {}", v.type_name()))),
                };
                Ok(EvalResult::Value(Value::Bool(json.is_null())))
            }

            BuiltinFn::JsonKeys => {
                // Json.keys(json) -> Option<List<String>>
                let json = match &args[0] {
                    Value::Json(j) => j,
                    v => return Err(err(&format!("Json.keys expects Json, got {}", v.type_name()))),
                };
                match json.as_object() {
                    Some(obj) => {
                        let keys: Vec<Value> = obj.keys().map(|k| Value::String(k.clone())).collect();
                        Ok(EvalResult::Value(Value::Constructor {
                            name: "Some".to_string(),
                            fields: vec![Value::List(keys)],
                        }))
                    }
                    None => Ok(EvalResult::Value(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    })),
                }
            }

            // JSON constructors
            BuiltinFn::JsonNull => {
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Null)))
            }

            BuiltinFn::JsonBool => {
                let b = Self::expect_arg_1::<bool>(&args, "Json.bool", span)?;
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Bool(b))))
            }

            BuiltinFn::JsonNumber => {
                let n = match &args[0] {
                    Value::Float(f) => serde_json::Number::from_f64(*f)
                        .ok_or_else(|| err("Invalid float for JSON"))?,
                    Value::Int(i) => serde_json::Number::from(*i),
                    v => return Err(err(&format!("Json.number expects Float or Int, got {}", v.type_name()))),
                };
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Number(n))))
            }

            BuiltinFn::JsonInt => {
                let n = Self::expect_arg_1::<i64>(&args, "Json.int", span)?;
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Number(serde_json::Number::from(n)))))
            }

            BuiltinFn::JsonString => {
                let s = Self::expect_arg_1::<String>(&args, "Json.string", span)?;
                Ok(EvalResult::Value(Value::Json(serde_json::Value::String(s))))
            }

            BuiltinFn::JsonArray => {
                // Json.array(list: List<Json>) -> Json
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "Json.array", span)?;
                let arr: Result<Vec<serde_json::Value>, RuntimeError> = list.into_iter().map(|v| {
                    match v {
                        Value::Json(j) => Ok(j),
                        _ => Err(err("Json.array expects List<Json>")),
                    }
                }).collect();
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Array(arr?))))
            }

            BuiltinFn::JsonObject => {
                // Json.object(entries: List<(String, Json)>) -> Json
                let list = Self::expect_arg_1::<Vec<Value>>(&args, "Json.object", span)?;
                let mut map = serde_json::Map::new();
                for item in list {
                    match item {
                        Value::Tuple(fields) if fields.len() == 2 => {
                            let key = match &fields[0] {
                                Value::String(s) => s.clone(),
                                _ => return Err(err("Json.object expects (String, Json) tuples")),
                            };
                            let value = match &fields[1] {
                                Value::Json(j) => j.clone(),
                                _ => return Err(err("Json.object expects (String, Json) tuples")),
                            };
                            map.insert(key, value);
                        }
                        _ => return Err(err("Json.object expects List<(String, Json)>")),
                    }
                }
                Ok(EvalResult::Value(Value::Json(serde_json::Value::Object(map))))
            }
        }
    }

    // Helper functions for extracting typed arguments
    fn expect_arg_1<T>(args: &[Value], name: &str, span: Span) -> Result<T, RuntimeError>
    where
        T: TryFromValue,
    {
        if args.len() != 1 {
            return Err(RuntimeError {
                message: format!("{} requires 1 argument, got {}", name, args.len()),
                span: Some(span),
            });
        }
        T::try_from_value(&args[0]).ok_or_else(|| RuntimeError {
            message: format!("{} expects {} as argument", name, T::TYPE_NAME),
            span: Some(span),
        })
    }

    fn expect_args_2<T, U>(args: &[Value], name: &str, span: Span) -> Result<(T, U), RuntimeError>
    where
        T: TryFromValue,
        U: TryFromValue,
    {
        if args.len() != 2 {
            return Err(RuntimeError {
                message: format!("{} requires 2 arguments, got {}", name, args.len()),
                span: Some(span),
            });
        }
        let a = T::try_from_value(&args[0]).ok_or_else(|| RuntimeError {
            message: format!("{} expects {} as first argument", name, T::TYPE_NAME),
            span: Some(span),
        })?;
        let b = U::try_from_value(&args[1]).ok_or_else(|| RuntimeError {
            message: format!("{} expects {} as second argument", name, U::TYPE_NAME),
            span: Some(span),
        })?;
        Ok((a, b))
    }

    fn eval_match(
        &mut self,
        val: Value,
        arms: &[MatchArm],
        env: &Env,
        span: Span,
        tail: bool,
    ) -> Result<EvalResult, RuntimeError> {
        for arm in arms {
            if let Some(bindings) = self.match_pattern(&arm.pattern, &val) {
                let match_env = env.extend();
                for (name, value) in bindings {
                    match_env.define(name, value);
                }

                // Check guard if present
                if let Some(ref guard) = arm.guard {
                    let guard_val = self.eval_expr(guard, &match_env)?;
                    match guard_val {
                        Value::Bool(true) => {}
                        Value::Bool(false) => continue,
                        _ => {
                            return Err(RuntimeError {
                                message: "Match guard must be Bool".to_string(),
                                span: Some(arm.span),
                            });
                        }
                    }
                }

                // Match arm body is in tail position if the match itself is
                return self.eval_expr_tail(&arm.body, &match_env, tail);
            }
        }

        Err(RuntimeError {
            message: "No matching pattern".to_string(),
            span: Some(span),
        })
    }

    fn match_pattern(&self, pattern: &Pattern, value: &Value) -> Option<Vec<(String, Value)>> {
        match pattern {
            Pattern::Wildcard(_) => Some(Vec::new()),

            Pattern::Var(ident) => Some(vec![(ident.name.clone(), value.clone())]),

            Pattern::Literal(lit) => {
                let lit_val = self.eval_literal(lit);
                if self.values_equal(&lit_val, value) {
                    Some(Vec::new())
                } else {
                    None
                }
            }

            Pattern::Constructor { name, fields, .. } => match value {
                Value::Constructor {
                    name: val_name,
                    fields: val_fields,
                } => {
                    if name.name != *val_name {
                        return None;
                    }
                    if fields.len() != val_fields.len() {
                        return None;
                    }
                    let mut bindings = Vec::new();
                    for (pat, val) in fields.iter().zip(val_fields) {
                        bindings.extend(self.match_pattern(pat, val)?);
                    }
                    Some(bindings)
                }
                _ => None,
            },

            Pattern::Tuple { elements, .. } => match value {
                Value::Tuple(vals) => {
                    if elements.len() != vals.len() {
                        return None;
                    }
                    let mut bindings = Vec::new();
                    for (pat, val) in elements.iter().zip(vals) {
                        bindings.extend(self.match_pattern(pat, val)?);
                    }
                    Some(bindings)
                }
                _ => None,
            },

            Pattern::Record { fields, .. } => match value {
                Value::Record(val_fields) => {
                    let mut bindings = Vec::new();
                    for (name, pat) in fields {
                        let val = val_fields.get(&name.name)?;
                        bindings.extend(self.match_pattern(pat, val)?);
                    }
                    Some(bindings)
                }
                _ => None,
            },
        }
    }

    fn values_equal(&self, a: &Value, b: &Value) -> bool {
        match (a, b) {
            (Value::Int(a), Value::Int(b)) => a == b,
            (Value::Float(a), Value::Float(b)) => a == b,
            (Value::Bool(a), Value::Bool(b)) => a == b,
            (Value::String(a), Value::String(b)) => a == b,
            (Value::Char(a), Value::Char(b)) => a == b,
            (Value::Unit, Value::Unit) => true,
            (Value::List(a), Value::List(b)) => {
                a.len() == b.len() && a.iter().zip(b).all(|(x, y)| self.values_equal(x, y))
            }
            (Value::Tuple(a), Value::Tuple(b)) => {
                a.len() == b.len() && a.iter().zip(b).all(|(x, y)| self.values_equal(x, y))
            }
            (Value::Record(a), Value::Record(b)) => {
                a.len() == b.len() && a.iter().all(|(k, v)| {
                    b.get(k).map(|bv| self.values_equal(v, bv)).unwrap_or(false)
                })
            }
            (
                Value::Constructor {
                    name: n1,
                    fields: f1,
                },
                Value::Constructor {
                    name: n2,
                    fields: f2,
                },
            ) => {
                n1 == n2
                    && f1.len() == f2.len()
                    && f1.iter().zip(f2).all(|(x, y)| self.values_equal(x, y))
            }
            (Value::Json(a), Value::Json(b)) => a == b,
            _ => false,
        }
    }

    fn eval_run(
        &mut self,
        expr: &Expr,
        handlers: &[(Ident, Expr)],
        env: &Env,
        span: Span,
    ) -> Result<EvalResult, RuntimeError> {
        // Evaluate handlers and push onto stack
        let mut handler_values = Vec::new();
        for (effect_name, handler_expr) in handlers {
            let handler_val = self.eval_expr(handler_expr, env)?;
            match handler_val {
                Value::Handler(h) => {
                    if h.effect != effect_name.name {
                        return Err(RuntimeError {
                            message: format!(
                                "Handler for effect '{}' assigned to '{}'",
                                h.effect, effect_name.name
                            ),
                            span: Some(span),
                        });
                    }
                    handler_values.push(h);
                }
                _ => {
                    return Err(RuntimeError {
                        message: format!(
                            "Expected handler for effect '{}', got {}",
                            effect_name.name,
                            handler_val.type_name()
                        ),
                        span: Some(span),
                    });
                }
            }
        }

        // Push handlers onto stack (for nested handler semantics)
        for h in &handler_values {
            self.handler_stack.push(Rc::clone(h));
        }

        // Update evidence map for O(1) lookup (evidence passing optimization)
        // Save previous evidence values for restoration
        let mut previous_evidence: Vec<(String, Option<Rc<HandlerValue>>)> = Vec::new();
        for h in &handler_values {
            let effect_name = h.effect.clone();
            let prev = self.evidence.insert(effect_name.clone(), Rc::clone(h));
            previous_evidence.push((effect_name, prev));
        }

        // Evaluate expression
        let result = self.eval_expr_inner(expr, env);

        // Restore previous evidence (for proper nested handler support)
        for (effect_name, prev) in previous_evidence.into_iter().rev() {
            match prev {
                Some(h) => {
                    self.evidence.insert(effect_name, h);
                }
                None => {
                    self.evidence.remove(&effect_name);
                }
            }
        }

        // Pop handlers from stack
        for _ in &handler_values {
            self.handler_stack.pop();
        }

        result
    }

    fn handle_effect(&mut self, request: EffectRequest) -> Result<Value, RuntimeError> {
        let trace_enabled = self.trace_effects;
        let timestamp = if trace_enabled {
            self.start_time.elapsed().as_micros()
        } else {
            0
        };

        // Find a handler using evidence map (O(1) lookup via evidence passing)
        // This replaces the previous O(n) handler_stack search
        let handler_data: Option<(Env, crate::ast::Expr, Vec<Ident>)> = self
            .evidence
            .get(&request.effect)
            .and_then(|handler| {
                handler
                    .implementations
                    .get(&request.operation)
                    .map(|impl_| {
                        (
                            handler.env.clone(),
                            impl_.body.clone(),
                            impl_.params.clone(),
                        )
                    })
            });

        let result = if let Some((handler_env, body, params)) = handler_data {
            let env = handler_env.extend();
            for (i, param) in params.iter().enumerate() {
                if i < request.args.len() {
                    env.define(&param.name, request.args[i].clone());
                }
            }
            // Enter handler context (enables resume)
            self.in_handler_depth += 1;
            let eval_result = self.eval_expr_inner(&body, &env);
            self.in_handler_depth -= 1;

            // Handle Resume result - use the resumed value as the effect's return value
            match eval_result {
                Ok(EvalResult::Resume(value)) => Ok(value),
                Ok(EvalResult::Value(value)) => Ok(value),
                Ok(EvalResult::Effect(req)) => {
                    // Handler body can perform effects - handle them
                    self.handle_effect(req)
                }
                Ok(EvalResult::TailCall { func, args, span }) => {
                    // Tail call in handler - evaluate it
                    self.eval_call_to_value(func, args, span)
                }
                Err(e) => Err(e),
            }
        } else {
            // No handler found - check for built-in effects
            self.handle_builtin_effect(&request)
        };

        // Record trace if enabled
        if trace_enabled {
            self.effect_traces.push(EffectTrace {
                effect: request.effect.clone(),
                operation: request.operation.clone(),
                args: request.args.clone(),
                result: result.as_ref().ok().cloned(),
                timestamp_us: timestamp,
            });
        }

        result
    }

    fn handle_builtin_effect(&self, request: &EffectRequest) -> Result<Value, RuntimeError> {
        match (request.effect.as_str(), request.operation.as_str()) {
            ("Console", "print") => {
                if let Some(Value::String(s)) = request.args.first() {
                    println!("{}", s);
                    Ok(Value::Unit)
                } else if let Some(v) = request.args.first() {
                    println!("{}", v);
                    Ok(Value::Unit)
                } else {
                    Ok(Value::Unit)
                }
            }
            ("Console", "read") | ("Console", "readLine") => {
                let mut input = String::new();
                std::io::stdin()
                    .read_line(&mut input)
                    .map_err(|e| RuntimeError {
                        message: format!("Failed to read input: {}", e),
                        span: None,
                    })?;
                Ok(Value::String(input.trim().to_string()))
            }
            ("Console", "readInt") => {
                let mut input = String::new();
                std::io::stdin()
                    .read_line(&mut input)
                    .map_err(|e| RuntimeError {
                        message: format!("Failed to read input: {}", e),
                        span: None,
                    })?;
                let trimmed = input.trim();
                match trimmed.parse::<i64>() {
                    Ok(n) => Ok(Value::Int(n)),
                    Err(_) => Err(RuntimeError {
                        message: format!("Invalid integer: '{}'", trimmed),
                        span: None,
                    }),
                }
            }
            ("Fail", "fail") => {
                let msg = request
                    .args
                    .first()
                    .map(|v| format!("{}", v))
                    .unwrap_or_else(|| "Unknown error".to_string());
                Err(RuntimeError {
                    message: msg,
                    span: None,
                })
            }
            ("State", "get") => {
                Ok(self.builtin_state.borrow().clone())
            }
            ("State", "put") => {
                if let Some(value) = request.args.first() {
                    *self.builtin_state.borrow_mut() = value.clone();
                    Ok(Value::Unit)
                } else {
                    Err(RuntimeError {
                        message: "State.put requires a value argument".to_string(),
                        span: None,
                    })
                }
            }
            ("Reader", "ask") => {
                Ok(self.builtin_reader.borrow().clone())
            }
            ("Random", "int") => {
                let min = match request.args.first() {
                    Some(Value::Int(n)) => *n,
                    _ => 0,
                };
                let max = match request.args.get(1) {
                    Some(Value::Int(n)) => *n,
                    _ => i64::MAX,
                };
                let mut rng = rand::thread_rng();
                let value = rng.gen_range(min..=max);
                Ok(Value::Int(value))
            }
            ("Random", "float") => {
                let mut rng = rand::thread_rng();
                let value: f64 = rng.gen();
                Ok(Value::Float(value))
            }
            ("Random", "bool") => {
                let mut rng = rand::thread_rng();
                let value: bool = rng.gen();
                Ok(Value::Bool(value))
            }
            ("Time", "now") => {
                use std::time::{SystemTime, UNIX_EPOCH};
                let duration = SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap_or_default();
                let millis = duration.as_millis() as i64;
                Ok(Value::Int(millis))
            }
            ("Time", "sleep") => {
                use std::thread;
                use std::time::Duration;
                let ms = match request.args.first() {
                    Some(Value::Int(n)) => *n as u64,
                    _ => 0,
                };
                thread::sleep(Duration::from_millis(ms));
                Ok(Value::Unit)
            }

            // ===== File Effect =====
            ("File", "read") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.read requires a string path".to_string(),
                        span: None,
                    }),
                };
                match std::fs::read_to_string(&path) {
                    Ok(content) => Ok(Value::String(content)),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to read file '{}': {}", path, e),
                        span: None,
                    }),
                }
            }
            ("File", "write") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.write requires a string path".to_string(),
                        span: None,
                    }),
                };
                let content = match request.args.get(1) {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.write requires string content".to_string(),
                        span: None,
                    }),
                };
                match std::fs::write(&path, &content) {
                    Ok(()) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to write file '{}': {}", path, e),
                        span: None,
                    }),
                }
            }
            ("File", "append") => {
                use std::fs::OpenOptions;
                use std::io::Write;
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.append requires a string path".to_string(),
                        span: None,
                    }),
                };
                let content = match request.args.get(1) {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.append requires string content".to_string(),
                        span: None,
                    }),
                };
                match OpenOptions::new().create(true).append(true).open(&path) {
                    Ok(mut file) => {
                        file.write_all(content.as_bytes()).map_err(|e| RuntimeError {
                            message: format!("Failed to append to file '{}': {}", path, e),
                            span: None,
                        })?;
                        Ok(Value::Unit)
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to open file '{}': {}", path, e),
                        span: None,
                    }),
                }
            }
            ("File", "exists") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.exists requires a string path".to_string(),
                        span: None,
                    }),
                };
                Ok(Value::Bool(std::path::Path::new(&path).exists()))
            }
            ("File", "delete") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.delete requires a string path".to_string(),
                        span: None,
                    }),
                };
                match std::fs::remove_file(&path) {
                    Ok(()) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to delete file '{}': {}", path, e),
                        span: None,
                    }),
                }
            }
            ("File", "readDir") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.readDir requires a string path".to_string(),
                        span: None,
                    }),
                };
                match std::fs::read_dir(&path) {
                    Ok(entries) => {
                        let files: Vec<Value> = entries
                            .filter_map(|e| e.ok())
                            .map(|e| Value::String(e.file_name().to_string_lossy().to_string()))
                            .collect();
                        Ok(Value::List(files))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to read directory '{}': {}", path, e),
                        span: None,
                    }),
                }
            }
            ("File", "isDir") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.isDir requires a string path".to_string(),
                        span: None,
                    }),
                };
                Ok(Value::Bool(std::path::Path::new(&path).is_dir()))
            }
            ("File", "mkdir") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "File.mkdir requires a string path".to_string(),
                        span: None,
                    }),
                };
                match std::fs::create_dir_all(&path) {
                    Ok(()) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to create directory '{}': {}", path, e),
                        span: None,
                    }),
                }
            }

            // ===== Process Effect =====
            ("Process", "exec") => {
                use std::process::Command;
                let cmd = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Process.exec requires a string command".to_string(),
                        span: None,
                    }),
                };
                match Command::new("sh").arg("-c").arg(&cmd).output() {
                    Ok(output) => {
                        let stdout = String::from_utf8_lossy(&output.stdout).to_string();
                        Ok(Value::String(stdout))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to execute command: {}", e),
                        span: None,
                    }),
                }
            }
            ("Process", "execStatus") => {
                use std::process::Command;
                let cmd = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Process.execStatus requires a string command".to_string(),
                        span: None,
                    }),
                };
                match Command::new("sh").arg("-c").arg(&cmd).status() {
                    Ok(status) => {
                        let code = status.code().unwrap_or(-1) as i64;
                        Ok(Value::Int(code))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to execute command: {}", e),
                        span: None,
                    }),
                }
            }
            ("Process", "env") => {
                let var_name = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Process.env requires a string name".to_string(),
                        span: None,
                    }),
                };
                match std::env::var(&var_name) {
                    Ok(value) => Ok(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![Value::String(value)],
                    }),
                    Err(_) => Ok(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    }),
                }
            }
            ("Process", "args") => {
                let args: Vec<Value> = std::env::args()
                    .skip(1) // Skip the program name
                    .map(Value::String)
                    .collect();
                Ok(Value::List(args))
            }
            ("Process", "exit") => {
                let code = match request.args.first() {
                    Some(Value::Int(n)) => *n as i32,
                    _ => 0,
                };
                std::process::exit(code);
            }
            ("Process", "cwd") => {
                match std::env::current_dir() {
                    Ok(path) => Ok(Value::String(path.to_string_lossy().to_string())),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to get current directory: {}", e),
                        span: None,
                    }),
                }
            }
            ("Process", "setCwd") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Process.setCwd requires a string path".to_string(),
                        span: None,
                    }),
                };
                match std::env::set_current_dir(&path) {
                    Ok(()) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to change directory to '{}': {}", path, e),
                        span: None,
                    }),
                }
            }

            // ===== Http Effect =====
            ("Http", "get") => {
                let url = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Http.get requires a URL string".to_string(),
                        span: None,
                    }),
                };
                self.http_request("GET", &url, None)
            }
            ("Http", "post") => {
                let (url, body) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::String(u)), Some(Value::String(b))) => (u.clone(), b.clone()),
                    _ => return Err(RuntimeError {
                        message: "Http.post requires URL and body strings".to_string(),
                        span: None,
                    }),
                };
                self.http_request("POST", &url, Some(&body))
            }
            ("Http", "postJson") => {
                let (url, json) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::String(u)), Some(Value::Json(j))) => (u.clone(), j.clone()),
                    _ => return Err(RuntimeError {
                        message: "Http.postJson requires URL string and Json value".to_string(),
                        span: None,
                    }),
                };
                self.http_request_json("POST", &url, &json)
            }
            ("Http", "put") => {
                let (url, body) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::String(u)), Some(Value::String(b))) => (u.clone(), b.clone()),
                    _ => return Err(RuntimeError {
                        message: "Http.put requires URL and body strings".to_string(),
                        span: None,
                    }),
                };
                self.http_request("PUT", &url, Some(&body))
            }
            ("Http", "delete") => {
                let url = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Http.delete requires a URL string".to_string(),
                        span: None,
                    }),
                };
                self.http_request("DELETE", &url, None)
            }
            ("Http", "setHeader") => {
                // Headers would need to be stored in interpreter state
                // For now, this is a no-op placeholder
                Ok(Value::Unit)
            }
            ("Http", "setTimeout") => {
                // Timeout would need to be stored in interpreter state
                // For now, this is a no-op placeholder
                Ok(Value::Unit)
            }

            // ===== HttpServer Effect =====
            ("HttpServer", "listen") => {
                let port = match request.args.first() {
                    Some(Value::Int(p)) => *p as u16,
                    _ => return Err(RuntimeError {
                        message: "HttpServer.listen requires an integer port".to_string(),
                        span: None,
                    }),
                };

                let addr = format!("0.0.0.0:{}", port);
                match tiny_http::Server::http(&addr) {
                    Ok(server) => {
                        *self.http_server.lock().unwrap() = Some(server);
                        Ok(Value::Unit)
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Failed to start HTTP server on port {}: {}", port, e),
                        span: None,
                    }),
                }
            }
            ("HttpServer", "accept") => {
                let server_guard = self.http_server.lock().unwrap();
                let server = match server_guard.as_ref() {
                    Some(s) => s,
                    None => return Err(RuntimeError {
                        message: "HttpServer.accept: No server is listening. Call HttpServer.listen first.".to_string(),
                        span: None,
                    }),
                };

                // Block until a request arrives
                match server.recv() {
                    Ok(mut request) => {
                        // Extract request info
                        let method = request.method().to_string();
                        let path = request.url().to_string();

                        // Read body
                        let mut body = String::new();
                        let _ = std::io::Read::read_to_string(&mut request.as_reader(), &mut body);

                        // Extract headers
                        let headers: Vec<Value> = request.headers()
                            .iter()
                            .map(|h| Value::Tuple(vec![
                                Value::String(h.field.as_str().to_string()),
                                Value::String(h.value.as_str().to_string()),
                            ]))
                            .collect();

                        // Store the request for respond operation
                        drop(server_guard); // Release lock before storing request
                        *self.current_http_request.lock().unwrap() = Some(request);

                        // Return request as a record
                        Ok(Value::Record(HashMap::from([
                            ("method".to_string(), Value::String(method)),
                            ("path".to_string(), Value::String(path)),
                            ("body".to_string(), Value::String(body)),
                            ("headers".to_string(), Value::List(headers)),
                        ])))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("HttpServer.accept failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("HttpServer", "respond") => {
                let (status, body) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(s)), Some(Value::String(b))) => (*s as u16, b.clone()),
                    _ => return Err(RuntimeError {
                        message: "HttpServer.respond requires status (Int) and body (String)".to_string(),
                        span: None,
                    }),
                };

                let mut req_guard = self.current_http_request.lock().unwrap();
                match req_guard.take() {
                    Some(http_request) => {
                        let status_code = tiny_http::StatusCode(status);
                        let response = tiny_http::Response::from_string(body)
                            .with_status_code(status_code);
                        if let Err(e) = http_request.respond(response) {
                            return Err(RuntimeError {
                                message: format!("Failed to send HTTP response: {}", e),
                                span: None,
                            });
                        }
                        Ok(Value::Unit)
                    }
                    None => Err(RuntimeError {
                        message: "HttpServer.respond: No pending request to respond to".to_string(),
                        span: None,
                    }),
                }
            }
            ("HttpServer", "respondWithHeaders") => {
                let (status, body, headers) = match (request.args.get(0), request.args.get(1), request.args.get(2)) {
                    (Some(Value::Int(s)), Some(Value::String(b)), Some(Value::List(h))) => {
                        (*s as u16, b.clone(), h.clone())
                    }
                    _ => return Err(RuntimeError {
                        message: "HttpServer.respondWithHeaders requires status (Int), body (String), and headers (List)".to_string(),
                        span: None,
                    }),
                };

                let mut req_guard = self.current_http_request.lock().unwrap();
                match req_guard.take() {
                    Some(http_request) => {
                        let status_code = tiny_http::StatusCode(status);
                        let mut response = tiny_http::Response::from_string(body)
                            .with_status_code(status_code);

                        // Add custom headers
                        for header_val in headers {
                            if let Value::Tuple(pair) = header_val {
                                if let (Some(Value::String(name)), Some(Value::String(value))) =
                                    (pair.get(0), pair.get(1))
                                {
                                    if let Ok(header) = tiny_http::Header::from_bytes(
                                        name.as_bytes(),
                                        value.as_bytes(),
                                    ) {
                                        response = response.with_header(header);
                                    }
                                }
                            }
                        }

                        if let Err(e) = http_request.respond(response) {
                            return Err(RuntimeError {
                                message: format!("Failed to send HTTP response: {}", e),
                                span: None,
                            });
                        }
                        Ok(Value::Unit)
                    }
                    None => Err(RuntimeError {
                        message: "HttpServer.respondWithHeaders: No pending request to respond to".to_string(),
                        span: None,
                    }),
                }
            }
            ("HttpServer", "stop") => {
                // Drop the server to stop listening
                *self.http_server.lock().unwrap() = None;
                *self.current_http_request.lock().unwrap() = None;
                Ok(Value::Unit)
            }

            // Test effect for testing framework
            ("Test", "assert") => {
                let condition = match request.args.first() {
                    Some(Value::Bool(b)) => *b,
                    _ => false,
                };
                let message = match request.args.get(1) {
                    Some(Value::String(s)) => s.clone(),
                    _ => "Assertion failed".to_string(),
                };

                if condition {
                    self.test_results.borrow_mut().passed += 1;
                } else {
                    self.test_results.borrow_mut().failed += 1;
                    self.test_results.borrow_mut().failures.push(TestFailure {
                        message,
                        expected: None,
                        actual: None,
                    });
                }
                Ok(Value::Unit)
            }
            ("Test", "assertEqual") => {
                let expected = request.args.first().cloned().unwrap_or(Value::Unit);
                let actual = request.args.get(1).cloned().unwrap_or(Value::Unit);

                if Value::values_equal(&expected, &actual) {
                    self.test_results.borrow_mut().passed += 1;
                } else {
                    self.test_results.borrow_mut().failed += 1;
                    self.test_results.borrow_mut().failures.push(TestFailure {
                        message: "Values not equal".to_string(),
                        expected: Some(format!("{}", expected)),
                        actual: Some(format!("{}", actual)),
                    });
                }
                Ok(Value::Unit)
            }
            ("Test", "assertNotEqual") => {
                let a = request.args.first().cloned().unwrap_or(Value::Unit);
                let b = request.args.get(1).cloned().unwrap_or(Value::Unit);

                if !Value::values_equal(&a, &b) {
                    self.test_results.borrow_mut().passed += 1;
                } else {
                    self.test_results.borrow_mut().failed += 1;
                    self.test_results.borrow_mut().failures.push(TestFailure {
                        message: "Values should not be equal".to_string(),
                        expected: Some(format!("not {}", a)),
                        actual: Some(format!("{}", b)),
                    });
                }
                Ok(Value::Unit)
            }
            ("Test", "assertTrue") => {
                let condition = match request.args.first() {
                    Some(Value::Bool(b)) => *b,
                    _ => false,
                };

                if condition {
                    self.test_results.borrow_mut().passed += 1;
                } else {
                    self.test_results.borrow_mut().failed += 1;
                    self.test_results.borrow_mut().failures.push(TestFailure {
                        message: "Expected true".to_string(),
                        expected: Some("true".to_string()),
                        actual: Some("false".to_string()),
                    });
                }
                Ok(Value::Unit)
            }
            ("Test", "assertFalse") => {
                let condition = match request.args.first() {
                    Some(Value::Bool(b)) => *b,
                    _ => true,
                };

                if !condition {
                    self.test_results.borrow_mut().passed += 1;
                } else {
                    self.test_results.borrow_mut().failed += 1;
                    self.test_results.borrow_mut().failures.push(TestFailure {
                        message: "Expected false".to_string(),
                        expected: Some("false".to_string()),
                        actual: Some("true".to_string()),
                    });
                }
                Ok(Value::Unit)
            }
            ("Test", "fail") => {
                let message = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => "Test failed".to_string(),
                };
                self.test_results.borrow_mut().failed += 1;
                self.test_results.borrow_mut().failures.push(TestFailure {
                    message,
                    expected: None,
                    actual: None,
                });
                Ok(Value::Unit)
            }

            // ===== Sql Effect =====
            ("Sql", "open") => {
                let path = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Sql.open requires a path string".to_string(),
                        span: None,
                    }),
                };

                match Connection::open(&path) {
                    Ok(conn) => {
                        let id = *self.next_sql_conn_id.borrow();
                        *self.next_sql_conn_id.borrow_mut() += 1;
                        self.sql_connections.borrow_mut().insert(id, conn);
                        Ok(Value::Int(id))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.open failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "openMemory") => {
                match Connection::open_in_memory() {
                    Ok(conn) => {
                        let id = *self.next_sql_conn_id.borrow();
                        *self.next_sql_conn_id.borrow_mut() += 1;
                        self.sql_connections.borrow_mut().insert(id, conn);
                        Ok(Value::Int(id))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.openMemory failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "close") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Sql.close requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                if self.sql_connections.borrow_mut().remove(&conn_id).is_some() {
                    Ok(Value::Unit)
                } else {
                    Err(RuntimeError {
                        message: format!("Sql.close: invalid connection ID {}", conn_id),
                        span: None,
                    })
                }
            }
            ("Sql", "execute") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Sql.execute requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.execute: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute(&sql, []) {
                    Ok(rows_affected) => Ok(Value::Int(rows_affected as i64)),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.execute failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "query") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Sql.query requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.query: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                let mut stmt = match conn.prepare(&sql) {
                    Ok(s) => s,
                    Err(e) => return Err(RuntimeError {
                        message: format!("Sql.query prepare failed: {}", e),
                        span: None,
                    }),
                };

                let column_names: Vec<String> = stmt.column_names().iter().map(|s| s.to_string()).collect();
                let column_count = column_names.len();

                let rows: Result<Vec<Value>, _> = stmt.query_map([], |row| {
                    let mut record = HashMap::new();
                    for (i, col_name) in column_names.iter().enumerate() {
                        let value = match row.get_ref(i) {
                            Ok(rusqlite::types::ValueRef::Null) => Value::Constructor {
                                name: "None".to_string(),
                                fields: vec![],
                            },
                            Ok(rusqlite::types::ValueRef::Integer(n)) => Value::Int(n),
                            Ok(rusqlite::types::ValueRef::Real(f)) => Value::Float(f),
                            Ok(rusqlite::types::ValueRef::Text(s)) => {
                                Value::String(String::from_utf8_lossy(s).to_string())
                            }
                            Ok(rusqlite::types::ValueRef::Blob(b)) => {
                                Value::String(format!("<blob {} bytes>", b.len()))
                            }
                            Err(_) => Value::String("<error>".to_string()),
                        };
                        record.insert(col_name.clone(), value);
                    }
                    Ok(Value::Record(record))
                }).and_then(|rows| rows.collect());

                match rows {
                    Ok(r) => Ok(Value::List(r)),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.query failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "queryOne") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Sql.queryOne requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.queryOne: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                let mut stmt = match conn.prepare(&sql) {
                    Ok(s) => s,
                    Err(e) => return Err(RuntimeError {
                        message: format!("Sql.queryOne prepare failed: {}", e),
                        span: None,
                    }),
                };

                let column_names: Vec<String> = stmt.column_names().iter().map(|s| s.to_string()).collect();

                let result = stmt.query_row([], |row| {
                    let mut record = HashMap::new();
                    for (i, col_name) in column_names.iter().enumerate() {
                        let value = match row.get_ref(i) {
                            Ok(rusqlite::types::ValueRef::Null) => Value::Constructor {
                                name: "None".to_string(),
                                fields: vec![],
                            },
                            Ok(rusqlite::types::ValueRef::Integer(n)) => Value::Int(n),
                            Ok(rusqlite::types::ValueRef::Real(f)) => Value::Float(f),
                            Ok(rusqlite::types::ValueRef::Text(s)) => {
                                Value::String(String::from_utf8_lossy(s).to_string())
                            }
                            Ok(rusqlite::types::ValueRef::Blob(b)) => {
                                Value::String(format!("<blob {} bytes>", b.len()))
                            }
                            Err(_) => Value::String("<error>".to_string()),
                        };
                        record.insert(col_name.clone(), value);
                    }
                    Ok(Value::Record(record))
                });

                match result {
                    Ok(row) => Ok(Value::Constructor {
                        name: "Some".to_string(),
                        fields: vec![row],
                    }),
                    Err(rusqlite::Error::QueryReturnedNoRows) => Ok(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    }),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.queryOne failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "beginTx") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Sql.beginTx requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.beginTx: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("BEGIN TRANSACTION", []) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.beginTx failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "commit") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Sql.commit requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.commit: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("COMMIT", []) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.commit failed: {}", e),
                        span: None,
                    }),
                }
            }
            ("Sql", "rollback") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Sql.rollback requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let conns = self.sql_connections.borrow();
                let conn = match conns.get(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Sql.rollback: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("ROLLBACK", []) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Sql.rollback failed: {}", e),
                        span: None,
                    }),
                }
            }

            // ============================================================
            // PostgreSQL Effect
            // ============================================================

            ("Postgres", "connect") => {
                let conn_str = match request.args.first() {
                    Some(Value::String(s)) => s.clone(),
                    _ => return Err(RuntimeError {
                        message: "Postgres.connect requires a connection string".to_string(),
                        span: None,
                    }),
                };

                match PgClient::connect(&conn_str, NoTls) {
                    Ok(client) => {
                        let id = *self.next_pg_conn_id.borrow();
                        *self.next_pg_conn_id.borrow_mut() += 1;
                        self.pg_connections.borrow_mut().insert(id, client);
                        Ok(Value::Int(id))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.connect failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "close") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Postgres.close requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                if self.pg_connections.borrow_mut().remove(&conn_id).is_some() {
                    Ok(Value::Unit)
                } else {
                    Err(RuntimeError {
                        message: format!("Postgres.close: invalid connection ID {}", conn_id),
                        span: None,
                    })
                }
            }

            ("Postgres", "execute") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Postgres.execute requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.execute: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute(&sql, &[]) {
                    Ok(rows) => Ok(Value::Int(rows as i64)),
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.execute failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "query") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Postgres.query requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.query: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.query(&sql, &[]) {
                    Ok(rows) => {
                        let mut results = Vec::new();
                        for row in rows {
                            let mut record = HashMap::new();
                            for (i, col) in row.columns().iter().enumerate() {
                                let col_name = col.name().to_string();
                                let value: Value = match col.type_().name() {
                                    "int4" | "int8" | "int2" => {
                                        let v: Option<i64> = row.get(i);
                                        match v {
                                            Some(n) => Value::Int(n),
                                            None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                        }
                                    }
                                    "float4" | "float8" => {
                                        let v: Option<f64> = row.get(i);
                                        match v {
                                            Some(n) => Value::Float(n),
                                            None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                        }
                                    }
                                    "bool" => {
                                        let v: Option<bool> = row.get(i);
                                        match v {
                                            Some(b) => Value::Bool(b),
                                            None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                        }
                                    }
                                    "text" | "varchar" | "char" | "bpchar" | "name" => {
                                        let v: Option<String> = row.get(i);
                                        match v {
                                            Some(s) => Value::String(s),
                                            None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                        }
                                    }
                                    _ => {
                                        // Try to get as string for other types
                                        let v: Option<String> = row.try_get(i).ok().flatten();
                                        match v {
                                            Some(s) => Value::String(s),
                                            None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                        }
                                    }
                                };
                                record.insert(col_name, value);
                            }
                            results.push(Value::Record(record));
                        }
                        Ok(Value::List(results))
                    }
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.query failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "queryOne") => {
                let (conn_id, sql) = match (request.args.get(0), request.args.get(1)) {
                    (Some(Value::Int(id)), Some(Value::String(s))) => (*id, s.clone()),
                    _ => return Err(RuntimeError {
                        message: "Postgres.queryOne requires connection ID and SQL string".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.queryOne: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.query_opt(&sql, &[]) {
                    Ok(Some(row)) => {
                        let mut record = HashMap::new();
                        for (i, col) in row.columns().iter().enumerate() {
                            let col_name = col.name().to_string();
                            let value: Value = match col.type_().name() {
                                "int4" | "int8" | "int2" => {
                                    let v: Option<i64> = row.get(i);
                                    match v {
                                        Some(n) => Value::Int(n),
                                        None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                    }
                                }
                                "float4" | "float8" => {
                                    let v: Option<f64> = row.get(i);
                                    match v {
                                        Some(n) => Value::Float(n),
                                        None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                    }
                                }
                                "bool" => {
                                    let v: Option<bool> = row.get(i);
                                    match v {
                                        Some(b) => Value::Bool(b),
                                        None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                    }
                                }
                                "text" | "varchar" | "char" | "bpchar" | "name" => {
                                    let v: Option<String> = row.get(i);
                                    match v {
                                        Some(s) => Value::String(s),
                                        None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                    }
                                }
                                _ => {
                                    let v: Option<String> = row.try_get(i).ok().flatten();
                                    match v {
                                        Some(s) => Value::String(s),
                                        None => Value::Constructor { name: "None".to_string(), fields: vec![] },
                                    }
                                }
                            };
                            record.insert(col_name, value);
                        }
                        Ok(Value::Constructor {
                            name: "Some".to_string(),
                            fields: vec![Value::Record(record)],
                        })
                    }
                    Ok(None) => Ok(Value::Constructor {
                        name: "None".to_string(),
                        fields: vec![],
                    }),
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.queryOne failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "beginTx") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Postgres.beginTx requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.beginTx: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("BEGIN", &[]) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.beginTx failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "commit") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Postgres.commit requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.commit: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("COMMIT", &[]) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.commit failed: {}", e),
                        span: None,
                    }),
                }
            }

            ("Postgres", "rollback") => {
                let conn_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Postgres.rollback requires a connection ID".to_string(),
                        span: None,
                    }),
                };

                let mut conns = self.pg_connections.borrow_mut();
                let conn = match conns.get_mut(&conn_id) {
                    Some(c) => c,
                    None => return Err(RuntimeError {
                        message: format!("Postgres.rollback: invalid connection ID {}", conn_id),
                        span: None,
                    }),
                };

                match conn.execute("ROLLBACK", &[]) {
                    Ok(_) => Ok(Value::Unit),
                    Err(e) => Err(RuntimeError {
                        message: format!("Postgres.rollback failed: {}", e),
                        span: None,
                    }),
                }
            }

            // ===== Concurrent Effect =====
            ("Concurrent", "spawn") => {
                // For now, spawn just stores the thunk - it will be evaluated on await
                // In a real implementation, this would start a thread/fiber
                let thunk = match request.args.first() {
                    Some(v) => v.clone(),
                    _ => return Err(RuntimeError {
                        message: "Concurrent.spawn requires a thunk argument".to_string(),
                        span: None,
                    }),
                };

                let task_id = *self.next_task_id.borrow();
                *self.next_task_id.borrow_mut() += 1;

                // Store task: (thunk, None for result, not cancelled)
                self.concurrent_tasks.borrow_mut().insert(task_id, (thunk, None, false));

                Ok(Value::Int(task_id))
            }
            ("Concurrent", "await") => {
                let task_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Concurrent.await requires a task ID".to_string(),
                        span: None,
                    }),
                };

                // Check if already computed or cancelled
                let task_info = {
                    let tasks = self.concurrent_tasks.borrow();
                    tasks.get(&task_id).cloned()
                };

                match task_info {
                    Some((_, Some(result), _)) => Ok(result),
                    Some((_, _, true)) => Err(RuntimeError {
                        message: format!("Task {} was cancelled", task_id),
                        span: None,
                    }),
                    Some((thunk, None, false)) => {
                        // For cooperative concurrency, we just need to signal
                        // that we're waiting on this task
                        // Return the thunk to be evaluated by the caller
                        // This is a simplification - real async would use fibers
                        Ok(thunk)
                    }
                    None => Err(RuntimeError {
                        message: format!("Unknown task ID: {}", task_id),
                        span: None,
                    }),
                }
            }
            ("Concurrent", "yield") => {
                // In cooperative concurrency, yield allows other tasks to run
                // For now, this is a no-op in our single-threaded model
                Ok(Value::Unit)
            }
            ("Concurrent", "sleep") => {
                // Non-blocking sleep (delegates to thread sleep for now)
                use std::thread;
                use std::time::Duration;
                let ms = match request.args.first() {
                    Some(Value::Int(n)) => *n as u64,
                    _ => 0,
                };
                thread::sleep(Duration::from_millis(ms));
                Ok(Value::Unit)
            }
            ("Concurrent", "cancel") => {
                let task_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Concurrent.cancel requires a task ID".to_string(),
                        span: None,
                    }),
                };

                let mut tasks = self.concurrent_tasks.borrow_mut();
                if let Some((thunk, result, _)) = tasks.get(&task_id).cloned() {
                    tasks.insert(task_id, (thunk, result, true));
                    Ok(Value::Bool(true))
                } else {
                    Ok(Value::Bool(false))
                }
            }
            ("Concurrent", "isRunning") => {
                let task_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Concurrent.isRunning requires a task ID".to_string(),
                        span: None,
                    }),
                };

                let tasks = self.concurrent_tasks.borrow();
                let is_running = match tasks.get(&task_id) {
                    Some((_, None, false)) => true,  // Not completed and not cancelled
                    _ => false,
                };
                Ok(Value::Bool(is_running))
            }
            ("Concurrent", "taskCount") => {
                let tasks = self.concurrent_tasks.borrow();
                let count = tasks.iter()
                    .filter(|(_, (_, result, cancelled))| result.is_none() && !cancelled)
                    .count();
                Ok(Value::Int(count as i64))
            }

            // ===== Channel Effect =====
            ("Channel", "create") => {
                let channel_id = *self.next_channel_id.borrow();
                *self.next_channel_id.borrow_mut() += 1;

                // Create empty channel queue, not closed
                self.channels.borrow_mut().insert(channel_id, (Vec::new(), false));

                Ok(Value::Int(channel_id))
            }
            ("Channel", "send") => {
                let channel_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Channel.send requires a channel ID".to_string(),
                        span: None,
                    }),
                };
                let value = match request.args.get(1) {
                    Some(v) => v.clone(),
                    _ => return Err(RuntimeError {
                        message: "Channel.send requires a value".to_string(),
                        span: None,
                    }),
                };

                let mut channels = self.channels.borrow_mut();
                match channels.get_mut(&channel_id) {
                    Some((queue, false)) => {
                        queue.push(value);
                        Ok(Value::Unit)
                    }
                    Some((_, true)) => Err(RuntimeError {
                        message: format!("Channel {} is closed", channel_id),
                        span: None,
                    }),
                    None => Err(RuntimeError {
                        message: format!("Unknown channel ID: {}", channel_id),
                        span: None,
                    }),
                }
            }
            ("Channel", "receive") => {
                let channel_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Channel.receive requires a channel ID".to_string(),
                        span: None,
                    }),
                };

                let mut channels = self.channels.borrow_mut();
                match channels.get_mut(&channel_id) {
                    Some((queue, _)) if !queue.is_empty() => {
                        Ok(queue.remove(0))
                    }
                    Some((_, true)) => Err(RuntimeError {
                        message: format!("Channel {} is closed and empty", channel_id),
                        span: None,
                    }),
                    Some((_, false)) => Err(RuntimeError {
                        message: format!("Channel {} is empty (blocking receive not supported yet)", channel_id),
                        span: None,
                    }),
                    None => Err(RuntimeError {
                        message: format!("Unknown channel ID: {}", channel_id),
                        span: None,
                    }),
                }
            }
            ("Channel", "tryReceive") => {
                let channel_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Channel.tryReceive requires a channel ID".to_string(),
                        span: None,
                    }),
                };

                let mut channels = self.channels.borrow_mut();
                match channels.get_mut(&channel_id) {
                    Some((queue, _)) if !queue.is_empty() => {
                        Ok(Value::Constructor {
                            name: "Some".to_string(),
                            fields: vec![queue.remove(0)],
                        })
                    }
                    Some(_) => {
                        Ok(Value::Constructor {
                            name: "None".to_string(),
                            fields: vec![],
                        })
                    }
                    None => Err(RuntimeError {
                        message: format!("Unknown channel ID: {}", channel_id),
                        span: None,
                    }),
                }
            }
            ("Channel", "close") => {
                let channel_id = match request.args.first() {
                    Some(Value::Int(id)) => *id,
                    _ => return Err(RuntimeError {
                        message: "Channel.close requires a channel ID".to_string(),
                        span: None,
                    }),
                };

                let mut channels = self.channels.borrow_mut();
                if let Some((queue, closed)) = channels.get_mut(&channel_id) {
                    *closed = true;
                    Ok(Value::Unit)
                } else {
                    Err(RuntimeError {
                        message: format!("Unknown channel ID: {}", channel_id),
                        span: None,
                    })
                }
            }

            _ => Err(RuntimeError {
                message: format!(
                    "Unhandled effect operation: {}.{}",
                    request.effect, request.operation
                ),
                span: None,
            }),
        }
    }

    /// Helper for HTTP requests
    fn http_request(&self, method: &str, url: &str, body: Option<&str>) -> Result<Value, RuntimeError> {
        use reqwest::blocking::Client;

        let client = Client::new();
        let request = match method {
            "GET" => client.get(url),
            "POST" => {
                let req = client.post(url);
                if let Some(b) = body {
                    req.header("Content-Type", "text/plain").body(b.to_string())
                } else {
                    req
                }
            }
            "PUT" => {
                let req = client.put(url);
                if let Some(b) = body {
                    req.header("Content-Type", "text/plain").body(b.to_string())
                } else {
                    req
                }
            }
            "DELETE" => client.delete(url),
            _ => return Err(RuntimeError {
                message: format!("Unsupported HTTP method: {}", method),
                span: None,
            }),
        };

        match request.send() {
            Ok(response) => {
                let status = response.status().as_u16() as i64;
                let headers: Vec<Value> = response.headers()
                    .iter()
                    .map(|(name, value)| {
                        Value::Tuple(vec![
                            Value::String(name.to_string()),
                            Value::String(value.to_str().unwrap_or("").to_string()),
                        ])
                    })
                    .collect();
                let body = response.text().unwrap_or_default();

                let response_record = Value::Record(HashMap::from([
                    ("status".to_string(), Value::Int(status)),
                    ("body".to_string(), Value::String(body)),
                    ("headers".to_string(), Value::List(headers)),
                ]));

                Ok(Value::Constructor {
                    name: "Ok".to_string(),
                    fields: vec![response_record],
                })
            }
            Err(e) => {
                Ok(Value::Constructor {
                    name: "Err".to_string(),
                    fields: vec![Value::String(e.to_string())],
                })
            }
        }
    }

    /// Helper for HTTP requests with JSON body
    fn http_request_json(&self, method: &str, url: &str, json: &serde_json::Value) -> Result<Value, RuntimeError> {
        use reqwest::blocking::Client;

        let client = Client::new();
        let request = match method {
            "POST" => client.post(url).json(json),
            "PUT" => client.put(url).json(json),
            _ => return Err(RuntimeError {
                message: format!("Unsupported HTTP method for JSON: {}", method),
                span: None,
            }),
        };

        match request.send() {
            Ok(response) => {
                let status = response.status().as_u16() as i64;
                let headers: Vec<Value> = response.headers()
                    .iter()
                    .map(|(name, value)| {
                        Value::Tuple(vec![
                            Value::String(name.to_string()),
                            Value::String(value.to_str().unwrap_or("").to_string()),
                        ])
                    })
                    .collect();
                let body = response.text().unwrap_or_default();

                let response_record = Value::Record(HashMap::from([
                    ("status".to_string(), Value::Int(status)),
                    ("body".to_string(), Value::String(body)),
                    ("headers".to_string(), Value::List(headers)),
                ]));

                Ok(Value::Constructor {
                    name: "Ok".to_string(),
                    fields: vec![response_record],
                })
            }
            Err(e) => {
                Ok(Value::Constructor {
                    name: "Err".to_string(),
                    fields: vec![Value::String(e.to_string())],
                })
            }
        }
    }
}

impl Default for Interpreter {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn test_create_versioned() {
        let interp = Interpreter::new();
        let record = Value::Record(
            [("name".to_string(), Value::String("Alice".to_string()))]
                .into_iter()
                .collect(),
        );

        let versioned = interp.create_versioned("User", 1, record);

        match versioned {
            Value::Versioned {
                type_name,
                version,
                value,
            } => {
                assert_eq!(type_name, "User");
                assert_eq!(version, 1);
                match *value {
                    Value::Record(fields) => match fields.get("name") {
                        Some(Value::String(s)) => assert_eq!(s, "Alice"),
                        _ => panic!("Expected name field with String value"),
                    },
                    _ => panic!("Expected Record value"),
                }
            }
            _ => panic!("Expected Versioned value"),
        }
    }

    #[test]
    fn test_migrate_non_versioned_passthrough() {
        let mut interp = Interpreter::new();
        let value = Value::Int(42);

        let result = interp.migrate_value(value, 2).unwrap();

        match result {
            Value::Int(n) => assert_eq!(n, 42),
            _ => panic!("Expected Int value to pass through unchanged"),
        }
    }

    #[test]
    fn test_migrate_same_version() {
        let mut interp = Interpreter::new();
        let versioned = Value::Versioned {
            type_name: "User".to_string(),
            version: 2,
            value: Box::new(Value::String("test".to_string())),
        };

        let result = interp.migrate_value(versioned, 2).unwrap();

        match result {
            Value::Versioned { version, .. } => assert_eq!(version, 2),
            _ => panic!("Expected Versioned value"),
        }
    }

    #[test]
    fn test_migrate_downgrade_error() {
        let mut interp = Interpreter::new();
        let versioned = Value::Versioned {
            type_name: "User".to_string(),
            version: 3,
            value: Box::new(Value::String("test".to_string())),
        };

        let result = interp.migrate_value(versioned, 2);

        assert!(result.is_err());
        assert!(result.unwrap_err().message.contains("Cannot downgrade"));
    }

    #[test]
    fn test_migrate_with_auto_migration() {
        let mut interp = Interpreter::new();
        // No explicit migration registered - should auto-migrate
        let versioned = Value::Versioned {
            type_name: "User".to_string(),
            version: 1,
            value: Box::new(Value::String("test".to_string())),
        };

        let result = interp.migrate_value(versioned, 3).unwrap();

        match result {
            Value::Versioned { version, value, .. } => {
                assert_eq!(version, 3);
                // Value should be unchanged for auto-migration
                match *value {
                    Value::String(s) => assert_eq!(s, "test"),
                    _ => panic!("Expected String value"),
                }
            }
            _ => panic!("Expected Versioned value"),
        }
    }

    #[test]
    fn test_register_and_execute_migration() {
        let mut interp = Interpreter::new();

        // Create a simple migration that adds a field
        // Migration: old.name -> { name: old.name, email: "unknown" }
        let migration_body = Expr::Record {
            fields: vec![
                (
                    Ident::new("name", Span::default()),
                    Expr::Field {
                        object: Box::new(Expr::Var(Ident::new("old", Span::default()))),
                        field: Ident::new("name", Span::default()),
                        span: Span::default(),
                    },
                ),
                (
                    Ident::new("email", Span::default()),
                    Expr::Literal(Literal {
                        kind: LiteralKind::String("unknown@example.com".to_string()),
                        span: Span::default(),
                    }),
                ),
            ],
            span: Span::default(),
        };

        let stored_migration = StoredMigration {
            body: migration_body,
            env: Env::new(),
        };

        interp.register_migration("User", 1, stored_migration);

        // Create a v1 value
        let v1_user = Value::Versioned {
            type_name: "User".to_string(),
            version: 1,
            value: Box::new(Value::Record(
                [("name".to_string(), Value::String("Alice".to_string()))]
                    .into_iter()
                    .collect(),
            )),
        };

        // Migrate to v2
        let result = interp.migrate_value(v1_user, 2).unwrap();

        match result {
            Value::Versioned {
                type_name,
                version,
                value,
            } => {
                assert_eq!(type_name, "User");
                assert_eq!(version, 2);
                match *value {
                    Value::Record(fields) => {
                        match fields.get("name") {
                            Some(Value::String(s)) => assert_eq!(s, "Alice"),
                            _ => panic!("Expected name field with String value"),
                        }
                        match fields.get("email") {
                            Some(Value::String(s)) => assert_eq!(s, "unknown@example.com"),
                            _ => panic!("Expected email field with String value"),
                        }
                    }
                    _ => panic!("Expected Record value"),
                }
            }
            _ => panic!("Expected Versioned value"),
        }
    }

    #[test]
    fn test_migration_from_type_declaration() {
        use crate::parser::Parser;

        // Test that migrations defined in type declarations are registered and executed
        let source = r#"
            type User @v2 {
                name: String,
                email: String,

                from @v1 = { name: old.name, email: "default@example.com" }
            }

            // Create a v1 user using Schema.versioned
            let v1_user = Schema.versioned("User", 1, { name: "Alice" })

            // Migrate to v2 - should use the declared migration
            let v2_user = Schema.migrate(v1_user, 2)

            // Get the migrated value
            let version = Schema.getVersion(v2_user)
        "#;

        let program = Parser::parse_source(source).expect("parse failed");
        let mut interp = Interpreter::new();
        let result = interp.run(&program);

        assert!(result.is_ok(), "Interpreter failed: {:?}", result);
        let result_value = result.unwrap();

        // The last expression should be the version number
        assert_eq!(format!("{}", result_value), "2");
    }

    #[test]
    fn test_migration_chain() {
        use crate::parser::Parser;

        // Test that migrations chain correctly: v1 -> v2 -> v3
        let source = r#"
            type Config @v3 {
                host: String,
                port: Int,
                secure: Bool,

                from @v2 = { host: old.host, port: old.port, secure: true },
                from @v1 = { host: old.host, port: 8080 }
            }

            // Create v1 config
            let v1_config = Schema.versioned("Config", 1, { host: "localhost" })

            // Migrate directly to v3 - should go v1 -> v2 -> v3
            let v3_config = Schema.migrate(v1_config, 3)
            let version = Schema.getVersion(v3_config)
        "#;

        let program = Parser::parse_source(source).expect("parse failed");
        let mut interp = Interpreter::new();
        let result = interp.run(&program);

        assert!(result.is_ok(), "Interpreter failed: {:?}", result);
        assert_eq!(format!("{}", result.unwrap()), "3");
    }
}
