// FILE: src/parser/interpreter/eval.rs

use crate::parser::ast::{Expr, Stmt};
use crate::parser::types::{Value, FunctionValue, LambdaParam};
use crate::parser::interpreter::Interpreter;
use crate::parser::interpreter::utils::{
    bool_like, eval_bracketed_array, eval_keyed_array, assign_to_expr, assign_keyed_destructure,
};
use crate::parser::interpreter::apply;

fn err_with_pos<S: Into<String>>(msg: S, line: usize, col: usize) -> String {
    format!("(at line {}, col {}) {}", line, col, msg.into())
}

pub fn eval_expression(
    _interp: &mut Interpreter,
    expr_str: &str
) -> Result<Value, String> {
    let trimmed = expr_str.trim();

    if let Ok(i) = trimmed.parse::<i32>() {
        return Ok(Value::Int(i));
    }

    if trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() >= 2 {
        let inner = &trimmed[1..trimmed.len() - 1];
        return Ok(Value::StrArray(vec![inner.to_string()]));
    }

    Err(format!("eval_expression => unrecognized expr '{}'", expr_str))
}

impl Interpreter {
    pub fn exec_statement(&mut self, stmt: &Stmt) -> Result<Value, String> {
        match stmt {
            Stmt::ImportSo { path, line, col } => {
                if self.is_verbose() {
                    eprintln!("(Interpreter) extend => {}", path);
                }
                if !self.can_extend() {
                    return Err(err_with_pos("extend is disallowed", *line, *col));
                }
                let expr_for_legacy = format!("extend(\"{}\")", path);
                crate::modules::extend::handle_extend_call(self, &expr_for_legacy)
                    .map_err(|e| err_with_pos(format!("extend error: {}", e), *line, *col))
            }
            Stmt::Assignment { left, right, line: _line, col: _col } => {
                let right_val = self.eval_expression(right)?;
                assign_to_expr(self, left, right_val.clone())?;
                Ok(right_val)
            }
            Stmt::AssignmentDestructure { pattern, right, line: _line, col: _col } => {
                let right_val = self.eval_expression(right)?;
                assign_keyed_destructure(self, pattern, right_val.clone())?;
                Ok(right_val)
            }
            Stmt::AssignmentScoped { left, right, line: _line, col: _col } => {
                let val = self.eval_expression(right)?;
                match left {
                    Expr::Ident { name, .. } => {
                        self.set_variable(name, val.clone());
                        Ok(val)
                    }
                    _ => Err(err_with_pos("Left side of ^=-assignment must be a variable", *_line, *_col)),
                }
            }
            Stmt::ExprStmt { expr, line: _line, col: _col } => self.eval_expression(expr),
        }
    }

    pub fn eval_expression(&mut self, expr: &Expr) -> Result<Value, String> {
        use Expr::*;
        match expr {
            Number { value, .. } => Ok(Value::Int(*value)),
            NumberFloat { value, .. } => Ok(Value::Float(*value)),
            StrLit { value, .. } => Ok(Value::SingleString(value.clone())),
            Bool { value, .. } => Ok(Value::Bool(*value)),
            Ident { name, line, col } => {
                let v = self.lookup_variable(name)
                    .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *line, *col))?;
                match v {
                    Value::Ref(arc_mutex) => Ok(arc_mutex.lock().unwrap().clone()),
                    v => Ok(v),
                }
            }
            Ref { expr: inner, line, col } => {
                match &**inner {
                    Expr::Ident { name, line: n_line, col: n_col } => {
                        let storage = self.lookup_variable_storage(name)
                            .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *n_line, *n_col))?;
                        Ok(Value::Ref(storage))
                    }
                    _ => Err(err_with_pos("Can only take reference of a variable", *line, *col)),
                }
            }
            Placeholder { line: _line, col: _col } => Ok(Value::Placeholder),
            BracketedArray { items, line: _line, col: _col } => eval_bracketed_array(self, items),
            KeyedArray { pairs, line: _line, col: _col } => eval_keyed_array(self, pairs),
            FunctionCall { callee, args, line, col } => {
                let callee_val = self.eval_expression(callee)?;
                // Special-case for lambdas with LambdaParam::Ref:
                if let Value::Function(fb) = &callee_val {
                    if let FunctionValue::InlineLambdaAST { params, .. } = &**fb {
                        let mut arg_vals = Vec::new();
                        for (i, a_expr) in args.iter().enumerate() {
                            let use_ref = params.get(i)
                                .map(|p| matches!(p, LambdaParam::Ref(_)))
                                .unwrap_or(false);
                            if use_ref {
                                // Only Expr::Ident can be passed as variable reference
                                if let Expr::Ident { name, line: v_line, col: v_col } = a_expr {
                                    let storage = self.lookup_variable_storage(name)
                                        .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *v_line, *v_col))?;
                                    arg_vals.push(Value::Ref(storage));
                                } else {
                                    // fallback: just evaluate as value and wrap as new Ref
                                    let v = self.eval_expression(a_expr)?;
                                    arg_vals.push(Value::Ref(std::sync::Arc::new(std::sync::Mutex::new(v))));
                                }
                            } else {
                                arg_vals.push(self.eval_expression(a_expr)?);
                            }
                        }
                        return apply::apply_n_ary_function_value(self, fb.clone(), arg_vals);
                    }
                }
                // Otherwise, classic behavior
                let mut arg_vals = Vec::new();
                for a_expr in args {
                    arg_vals.push(self.eval_expression(a_expr)?);
                }
                match callee_val {
                    Value::Function(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
                    Value::InkTransform(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
                    Value::Stream(sh) => {
                        Err(err_with_pos(format!("Cannot call a Stream as a function: stream_id={}", sh.stream_id), *line, *col))
                    }
                    other => Err(err_with_pos(format!("Cannot call non-function: {:?}", other), *line, *col)),
                }
            }
            Index { base, index, line: _line, col: _col } => {
                let base_val = self.eval_expression(base)?;
                let idx_val = self.eval_expression(index)?;
                self.eval_index_expr(base_val, idx_val)
            }
            Gt { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_gt(lv, rv)
            }
            Lt { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_lt(lv, rv)
            }
            EqEq { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_eqeq(lv, rv)
            }
            Le { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_le(lv, rv)
            }
            Ge { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_ge(lv, rv)
            }
            Add { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_add(lv, rv)
            }
            Sub { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_sub(lv, rv)
            }
            Mul { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_mul(lv, rv)
            }
            Div { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_div(lv, rv)
            }
            Mod { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_mod(lv, rv)
            }
            Ternary { cond, if_true, if_false, line: _line, col: _col } => {
                let cval = self.eval_expression(cond)?;
                match cval {
                    Value::Bool(flag) => {
                        if flag {
                            self.eval_expression(if_true)
                        } else {
                            self.eval_expression(if_false)
                        }
                    }
                    Value::Int(i) => {
                        if i == 0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    Value::Float(f) => {
                        if f == 0.0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    Value::Long(l) => {
                        if l == 0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    _ => Err(err_with_pos("Ternary condition must be bool/int/float/long", *_line, *_col)),
                }
            }
            InlineLambdaAST { params, body, line: _line, col: _col } => {
                let fv = FunctionValue::InlineLambdaAST {
                    params: params.clone(),
                    body_expr: body.clone(),
                };
                Ok(Value::Function(Box::new(fv)))
            }
            Block { stmts, line: _line, col: _col } => {
                self.push_scope();
                let mut last_val = Value::Bool(true);
                for s in stmts {
                    let v = self.exec_statement(s)?;
                    last_val = v;
                }
                self.pop_scope();
                Ok(last_val)
            }
            UnaryMinus { expr: subexpr, line: _line, col: _col } => {
                let val = self.eval_expression(subexpr)?;
                match val {
                    Value::Int(i) => {
                        i.checked_neg()
                            .map(Value::Int)
                            .ok_or_else(|| err_with_pos("Overflow in unary minus", *_line, *_col))
                    }
                    Value::Long(l) => {
                        l.checked_neg()
                            .map(Value::Long)
                            .ok_or_else(|| err_with_pos("Overflow in unary minus (long)", *_line, *_col))
                    }
                    Value::Float(ff) => Ok(Value::Float(-ff)),
                    other => Err(err_with_pos(format!("Cannot apply unary minus to {:?}", other), *_line, *_col)),
                }
            }
            AndAnd { left, right, line: _line, col: _col } => {
                let left_val = self.eval_expression(left)?;
                let left_truth = bool_like(&left_val)?;
                if !left_truth {
                    Ok(Value::Bool(false))
                } else {
                    let right_val = self.eval_expression(right)?;
                    let right_truth = bool_like(&right_val)?;
                    Ok(Value::Bool(right_truth))
                }
            }
            UnaryNot { expr: subexpr, line: _line, col: _col } => {
                let val = self.eval_expression(subexpr)?;
                let truth = bool_like(&val)?;
                Ok(Value::Bool(!truth))
            }
            Ne { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_ne(lv, rv)
            }
            BitAnd { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitand(lv, rv)
            }
            OrOr { left, right, line: _line, col: _col } => {
                let left_val = self.eval_expression(left)?;
                let left_truth = bool_like(&left_val)?;
                if left_truth {
                    Ok(Value::Bool(true))
                } else {
                    let right_val = self.eval_expression(right)?;
                    let right_truth = bool_like(&right_val)?;
                    Ok(Value::Bool(right_truth))
                }
            }
            Shl { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_shl(lv, rv)
            }
            Shr { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_shr(lv, rv)
            }
            BitXor { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitxor(lv, rv)
            }
            BitTilde { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bittilde(lv, rv)
            }
            BitOr { left, right, line: _line, col: _col } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitor(lv, rv)
            }
        }
    }

    fn eval_index_expr(&mut self, base_val: Value, idx_val: Value) -> Result<Value, String> {
        let actual_base = match base_val {
            Value::Ref(arc_mutex) => arc_mutex.lock().unwrap().clone(),
            v => v,
        };
        match (actual_base, idx_val) {
            (Value::IntArray(xs), Value::Int(i)) => {
                let len = xs.len() as i32;
                let idx = if i < 0 { len + i } else { i };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(Value::Int(xs[idx as usize]))
            }
            (Value::FloatArray(ffs), Value::Int(i)) => {
                let len = ffs.len() as i32;
                let idx = if i < 0 { len + i } else { i };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(Value::Float(ffs[idx as usize]))
            }
            (Value::StrArray(ss), Value::Int(i)) => {
                let len = ss.len() as i32;
                let idx = if i < 0 { len + i } else { i };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(Value::SingleString(ss[idx as usize].clone()))
            }
            (Value::Int2DArray(rows), Value::Int(r)) => {
                let len = rows.len() as i32;
                let idx = if r < 0 { len + r } else { r };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(Value::IntArray(rows[idx as usize].clone()))
            }
            (Value::Float2DArray(rows), Value::Int(r)) => {
                let len = rows.len() as i32;
                let idx = if r < 0 { len + r } else { r };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(Value::FloatArray(rows[idx as usize].clone()))
            }
            (Value::MixedArray(items), Value::Int(i)) => {
                let len = items.len() as i32;
                let idx = if i < 0 { len + i } else { i };
                if idx < 0 || idx >= len {
                    return Ok(Value::Placeholder);
                }
                Ok(items[idx as usize].clone())
            }
            (Value::KeyedArray(map), Value::SingleString(key)) => {
                if let Some(v) = map.get(&key) {
                    Ok(v.clone())
                } else {
                    Ok(Value::Placeholder)
                }
            }
            (Value::KeyedArray(map), Value::StrArray(arr)) if arr.len() == 1 => {
                if let Some(v) = map.get(&arr[0]) {
                    Ok(v.clone())
                } else {
                    Ok(Value::Placeholder)
                }
            }
            (Value::KeyedArray(_), Value::Int(_)) => {
                Err("Cannot index into a KeyedArray with an integer".to_string())
            }
            other => Err(format!("Cannot index into {:?}", other)),
        }
    }
}
