use evalexpr::*;
use std::collections::HashMap;
use std::io::{self, Write};

// Type aliases for the default numeric types
type Val = Value<DefaultNumericTypes>;
type Ctx = HashMapContext<DefaultNumericTypes>;
type Err = EvalexprError<DefaultNumericTypes>;
type Func = Function<DefaultNumericTypes>;
type Nd = Node<DefaultNumericTypes>;

/// Cached user-defined function with its parsed AST and parameter names
#[derive(Clone)]
struct UserFunction {
    params: Vec<String>,
    body: Nd,
}

/// The calculator REPL state
struct Calculator {
    /// The evalexpr context holding variables and built-in function access
    context: Ctx,
    /// User-defined functions (cached ASTs)
    user_functions: HashMap<String, UserFunction>,
}

/// Converts val to f64, None if not possible
fn value_to_f64(v: &Val) -> Option<f64> {
    v.as_float()
        .ok()
        .or_else(|| v.as_int().ok().map(|i| i as f64))
}

impl Calculator {
    fn new() -> Self {
        let mut context = Ctx::new();

        // builtin functions
        // sqrt function
        let _ = context.set_function(
            "sqrt".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.sqrt())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // sin function
        let _ = context.set_function(
            "sin".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.sin())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // cos function
        let _ = context.set_function(
            "cos".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.cos())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // tan function
        let _ = context.set_function(
            "tan".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.tan())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // asin function
        let _ = context.set_function(
            "asin".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.asin())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // acos function
        let _ = context.set_function(
            "acos".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.acos())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // atan function
        let _ = context.set_function(
            "atan".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.atan())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // sinh function
        let _ = context.set_function(
            "sinh".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.sinh())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // cosh function
        let _ = context.set_function(
            "cosh".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.cosh())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // tanh function
        let _ = context.set_function(
            "tanh".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.tanh())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // exp function
        let _ = context.set_function(
            "exp".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.exp())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // ln function
        let _ = context.set_function(
            "ln".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.ln())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // log10 function
        let _ = context.set_function(
            "log10".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.log10())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // log2 function
        let _ = context.set_function(
            "log2".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.log2())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // abs function
        let _ = context.set_function(
            "abs".into(),
            Func::new(|arg| {
                if let Ok(i) = arg.as_int() {
                    Ok(Val::from_int(i.abs()))
                } else if let Ok(f) = arg.as_float() {
                    Ok(Val::from_float(f.abs()))
                } else {
                    Err(Err::expected_number(arg.clone()))
                }
            }),
        );

        // floor function
        let _ = context.set_function(
            "floor".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.floor())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // ceil function
        let _ = context.set_function(
            "ceil".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.ceil())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // round function
        let _ = context.set_function(
            "round".into(),
            Func::new(|arg| match value_to_f64(arg) {
                Some(f) => Ok(Val::from_float(f.round())),
                None => Err(Err::expected_number(arg.clone())),
            }),
        );

        // pow function (2 arguments)
        let _ = context.set_function(
            "pow".into(),
            Func::new(|arg| {
                if let Ok(tuple) = arg.as_tuple() {
                    if tuple.len() == 2 {
                        let base = value_to_f64(&tuple[0])
                            .ok_or_else(|| Err::expected_number(tuple[0].clone()))?;
                        let exp = value_to_f64(&tuple[1])
                            .ok_or_else(|| Err::expected_number(tuple[1].clone()))?;
                        Ok(Val::from_float(base.powf(exp)))
                    } else {
                        Err(Err::WrongFunctionArgumentAmount {
                            expected: 2..=2,
                            actual: tuple.len(),
                        })
                    }
                } else {
                    Err(Err::ExpectedTuple {
                        actual: arg.clone(),
                    })
                }
            }),
        );

        // min function (2 arguments)
        let _ = context.set_function(
            "min".into(),
            Func::new(|arg| {
                if let Ok(tuple) = arg.as_tuple() {
                    if tuple.len() == 2 {
                        let a = value_to_f64(&tuple[0])
                            .ok_or_else(|| Err::expected_number(tuple[0].clone()))?;
                        let b = value_to_f64(&tuple[1])
                            .ok_or_else(|| Err::expected_number(tuple[1].clone()))?;
                        Ok(Val::from_float(a.min(b)))
                    } else {
                        Err(Err::WrongFunctionArgumentAmount {
                            expected: 2..=2,
                            actual: tuple.len(),
                        })
                    }
                } else {
                    Err(Err::ExpectedTuple {
                        actual: arg.clone(),
                    })
                }
            }),
        );

        // max function (2 arguments)
        let _ = context.set_function(
            "max".into(),
            Func::new(|arg| {
                if let Ok(tuple) = arg.as_tuple() {
                    if tuple.len() == 2 {
                        let a = value_to_f64(&tuple[0])
                            .ok_or_else(|| Err::expected_number(tuple[0].clone()))?;
                        let b = value_to_f64(&tuple[1])
                            .ok_or_else(|| Err::expected_number(tuple[1].clone()))?;
                        Ok(Val::from_float(a.max(b)))
                    } else {
                        Err(Err::WrongFunctionArgumentAmount {
                            expected: 2..=2,
                            actual: tuple.len(),
                        })
                    }
                } else {
                    Err(Err::ExpectedTuple {
                        actual: arg.clone(),
                    })
                }
            }),
        );

        // Add mathematical constants
        let _ = context.set_value("pi".into(), Val::from_float(std::f64::consts::PI));
        let _ = context.set_value("e".into(), Val::from_float(std::f64::consts::E));

        Self {
            context,
            user_functions: HashMap::new(),
        }
    }

    /// Evaluate an expression string
    fn evaluate(&mut self, expr: &str) -> Result<Val, Err> {
        // First, check if the expression is a user function call
        if let Some(result) = self.try_user_function(expr)? {
            return Ok(result);
        }

        // Use eval_with_context_mut
        eval_with_context_mut(expr, &mut self.context)
    }

    /// Try to parse and execute a user function call like `double(5)`
    fn try_user_function(&mut self, expr: &str) -> Result<Option<Val>, Err> {
        let expr = expr.trim();

        let Some(paren_pos) = expr.find('(') else {
            return Ok(None);
        };

        if !expr.ends_with(')') {
            return Ok(None);
        }

        let func_name = expr[..paren_pos].trim();

        if let Some(user_func) = self.user_functions.get(func_name).cloned() {
            let args_str = &expr[paren_pos + 1..expr.len() - 1];
            let arg_values = self.parse_arguments(args_str)?;

            if arg_values.len() != user_func.params.len() {
                return Err(Err::WrongFunctionArgumentAmount {
                    expected: user_func.params.len()..=user_func.params.len(),
                    actual: arg_values.len(),
                });
            }

            // Clone the main context to get access to custom functions
            let mut func_context = self.context.clone();

            // Bind parameters
            for (param, value) in user_func.params.iter().zip(arg_values) {
                func_context.set_value(param.clone(), value)?;
            }

            return Ok(Some(
                user_func.body.eval_with_context_mut(&mut func_context)?,
            ));
        }

        Ok(None)
    }

    /// Parse comma-separated arguments
    fn parse_arguments(&mut self, args_str: &str) -> Result<Vec<Val>, Err> {
        if args_str.trim().is_empty() {
            return Ok(vec![]);
        }

        let mut values = Vec::new();
        let mut depth = 0;
        let mut current_arg = String::new();

        for ch in args_str.chars() {
            match ch {
                '(' => {
                    depth += 1;
                    current_arg.push(ch);
                }
                ')' => {
                    depth -= 1;
                    current_arg.push(ch);
                }
                ',' if depth == 0 => {
                    let arg = current_arg.trim();
                    if !arg.is_empty() {
                        values.push(self.evaluate(arg)?);
                    }
                    current_arg.clear();
                }
                _ => current_arg.push(ch),
            }
        }

        let arg = current_arg.trim();
        if !arg.is_empty() {
            values.push(self.evaluate(arg)?);
        }

        Ok(values)
    }

    /// Define a variable: `var x = 42` or `let x = 42`
    fn define_variable(&mut self, input: &str) -> Result<(), String> {
        let parts: Vec<&str> = input.splitn(2, '=').collect();
        if parts.len() != 2 {
            return Err("Syntax: var <name> = <expression>".to_string());
        }

        let name = parts[0].trim();
        let expr = parts[1].trim();

        if name.is_empty() {
            return Err("Variable name cannot be empty".to_string());
        }

        if !is_valid_identifier(name) {
            return Err(format!("Invalid variable name: '{}'", name));
        }

        let value = self
            .evaluate(expr)
            .map_err(|e| format!("Error evaluating expression: {}", e))?;

        self.context
            .set_value(name.to_string(), value.clone())
            .map_err(|e| format!("Error setting variable: {}", e))?;

        println!("  {} = {}", name, value);
        Ok(())
    }

    /// Define a function: `func double(x) -> x * 2`
    fn define_function(&mut self, input: &str) -> Result<(), String> {
        let arrow_pos = input
            .find("->")
            .ok_or("Syntax: func <name>(<params>) -> <expression>")?;

        let signature = input[..arrow_pos].trim();
        let body_str = input[arrow_pos + 2..].trim();

        if body_str.is_empty() {
            return Err("Function body cannot be empty".to_string());
        }

        let paren_open = signature
            .find('(')
            .ok_or("Missing '(' in function signature")?;
        let paren_close = signature
            .find(')')
            .ok_or("Missing ')' in function signature")?;

        if paren_close < paren_open {
            return Err("Invalid function signature".to_string());
        }

        let name = signature[..paren_open].trim();
        let params_str = &signature[paren_open + 1..paren_close];

        if name.is_empty() {
            return Err("Function name cannot be empty".to_string());
        }

        if !is_valid_identifier(name) {
            return Err(format!("Invalid function name: '{}'", name));
        }

        let params: Vec<String> = if params_str.trim().is_empty() {
            vec![]
        } else {
            params_str
                .split(',')
                .map(|s| s.trim().to_string())
                .collect()
        };

        for param in &params {
            if !is_valid_identifier(param) {
                return Err(format!("Invalid parameter name: '{}'", param));
            }
        }

        // Parse and cache the function body AST
        let body = build_operator_tree(body_str)
            .map_err(|e| format!("Error parsing function body: {}", e))?;

        self.user_functions.insert(
            name.to_string(),
            UserFunction {
                params: params.clone(),
                body,
            },
        );

        let params_display = params.join(", ");
        println!("  Defined: {}({}) -> {}", name, params_display, body_str);
        Ok(())
    }

    /// List all variables and functions
    fn list_all(&self) {
        println!("\n  Variables:");
        let mut has_vars = false;
        for (name, value) in self.context.iter_variables() {
            println!("    {} = {}", name, value);
            has_vars = true;
        }
        if !has_vars {
            println!("    (none)");
        }

        println!("\n  User Functions:");
        if self.user_functions.is_empty() {
            println!("    (none)");
        } else {
            for (name, func) in &self.user_functions {
                let params = func.params.join(", ");
                println!("    {}({})", name, params);
            }
        }
        println!();
    }

    /// Show the help message
    fn show_help() {
        println!("\n  Calculator Commands:");
        println!("  ─────────────────────────────────────────────────────────────");
        println!("  <expression>              Evaluate an expression directly");
        println!("  var <name> = <expr>       Define a variable");
        println!("  let <name> = <expr>       Define a variable (alias)");
        println!("  func <name>(<args>) -> <expr>  Define a function");
        println!("  list                      Show all variables and functions");
        println!("  help                      Show this help message");
        println!("  quit / exit               Exit the calculator");
        println!();
        println!("  Built-in Functions:");
        println!("    Math: abs, floor, round, ceil, pow(x, y), min(a, b), max(a, b)");
        println!("    Trig: sin, cos, tan, asin, acos, atan, sinh, cosh, tanh");
        println!("    Logs: sqrt, exp, ln, log2, log10");
        println!("  Constants: pi, e");
        println!();
        println!("  Examples:");
        println!("    2 + 3 * 4");
        println!("    sqrt(16)");
        println!("    sin(pi / 2)");
        println!("    pow(2, 8)");
        println!("    var x = 10");
        println!("    func double(n) -> n * 2");
        println!("    func sqr(x) -> sqrt(x)");
        println!();
    }

    /// Process a single input line
    fn process_input(&mut self, input: &str, bench_mode: bool) -> bool {
        let input = input.trim();

        if input.is_empty() {
            return true;
        }

        match input.to_lowercase().as_str() {
            "quit" | "exit" => return false,
            "help" | "?" => {
                Self::show_help();
                return true;
            }
            "list" | "ls" => {
                self.list_all();
                return true;
            }
            _ => {}
        }

        if let Some(rest) = input
            .strip_prefix("var ")
            .or_else(|| input.strip_prefix("let "))
        {
            if let Err(e) = self.define_variable(rest) {
                println!("  Error: {}", e);
            }
            return true;
        }

        if let Some(rest) = input
            .strip_prefix("func ")
            .or_else(|| input.strip_prefix("fn "))
        {
            if let Err(e) = self.define_function(rest) {
                println!("  Error: {}", e);
            }
            return true;
        }
        if bench_mode {
            let start = std::time::Instant::now();
            match self.evaluate(input) {
                Ok(r) => {
                    println!("  = {}", r);
                    let duration = start.elapsed();
                    println!("  {}us", duration.as_micros());
                }
                Err(e) => println!("  {}", format_error(input, &e)),
            }
        } else {
            match self.evaluate(input) {
                Ok(value) => {
                    println!("  = {}", value)
                }
                Err(e) => println!("  {}", format_error(input, &e)),
            }
        }

        true
    }
}

/// Check if a string is a valid identifier
fn is_valid_identifier(s: &str) -> bool {
    if s.is_empty() {
        return false;
    }
    let mut chars = s.chars();
    let first = chars.next().unwrap();
    if !first.is_alphabetic() && first != '_' {
        return false;
    }
    chars.all(|c| c.is_alphanumeric() || c == '_')
}

/// Read a line from stdin, returning None on EOF
fn read_line() -> Option<String> {
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(0) => None,
        Ok(_) => Some(input),
        Err(e) => {
            eprintln!("  Error reading input: {}", e);
            Some(String::new())
        }
    }
}

fn format_error(input: &str, err: &Err) -> String {
    match err {
        Err::WrongOperatorArgumentAmount { expected, actual } => {
            format!(
                "Operator argument error:\n\
                 │ Input: {}\n\
                 │ Expected {} argument(s), but found {}",
                input, expected, actual
            )
        }
        Err::WrongFunctionArgumentAmount { expected, actual } => {
            let expected_str = if expected.start() == expected.end() {
                format!("{}", expected.start())
            } else {
                format!("{}-{}", expected.start(), expected.end())
            };
            format!(
                "Function argument error:\n\
                 │ Input: {}\n\
                 │ Expected {} argument(s), but found {}",
                input, expected_str, actual
            )
        }
        Err::ExpectedString { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a string, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedInt { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected an integer, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedFloat { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a float, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedNumber { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a number (int or float), but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedNumberOrString { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a number or string, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedBoolean { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a boolean, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedTuple { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a tuple, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedFixedLengthTuple {
            expected_length,
            actual,
        } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a tuple of length {}, but got {} ({})",
                input,
                expected_length,
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedRangedLengthTuple {
            expected_length,
            actual,
        } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected a tuple of length {}-{}, but got {} ({})",
                input,
                expected_length.start(),
                expected_length.end(),
                actual,
                value_type_name(actual)
            )
        }
        Err::ExpectedEmpty { actual } => {
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected empty value, but got {} ({})",
                input,
                actual,
                value_type_name(actual)
            )
        }
        Err::VariableIdentifierNotFound(name) => {
            let pointer = find_identifier_position(input, name);
            format!(
                "Undefined variable:\n\
                 │ Input: {}\n\
                 │        {}\n\
                 │ Variable '{}' is not defined.\n\
                 │ Hint: Define it with 'var {} = <value>' or check for typos.",
                input, pointer, name, name
            )
        }
        Err::FunctionIdentifierNotFound(name) => {
            let pointer = find_identifier_position(input, name);
            let suggestion = suggest_function(name);
            let hint = if let Some(suggested) = suggestion {
                format!("Did you mean '{}'?", suggested)
            } else {
                format!("Define it with 'func {}(...) -> <expression>'", name)
            };
            format!(
                "Undefined function:\n\
                 │ Input: {}\n\
                 │        {}\n\
                 │ Function '{}' is not defined.\n\
                 │ Hint: {}",
                input, pointer, name, hint
            )
        }
        Err::TypeError { expected, actual } => {
            let expected_str: Vec<_> = expected.iter().map(|t| format!("{:?}", t)).collect();
            format!(
                "Type error:\n\
                 │ Input: {}\n\
                 │ Expected one of [{}], but got {} ({})",
                input,
                expected_str.join(", "),
                actual,
                value_type_name(actual)
            )
        }
        Err::WrongTypeCombination { operator, actual } => {
            let types_str: Vec<_> = actual.iter().map(|t| format!("{:?}", t)).collect();
            format!(
                "Invalid type combination:\n\
                 │ Input: {}\n\
                 │ Operator '{:?}' cannot be used with types [{}]",
                input,
                operator,
                types_str.join(", ")
            )
        }
        Err::UnmatchedLBrace => {
            let pos = input.find('(').map(|p| p + 1);
            format!(
                "Syntax error - unmatched '(':\n\
                 │ Input: {}\n\
                 │        {}\n\
                 │ Opening parenthesis has no matching closing parenthesis.",
                input,
                pointer_at(pos)
            )
        }
        Err::UnmatchedRBrace => {
            let pos = input.rfind(')').map(|p| p + 1);
            format!(
                "Syntax error - unmatched ')':\n\
                 │ Input: {}\n\
                 │        {}\n\
                 │ Closing parenthesis has no matching opening parenthesis.",
                input,
                pointer_at(pos)
            )
        }
        Err::UnmatchedDoubleQuote => {
            let pos = input.find('"').map(|p| p + 1);
            format!(
                "Syntax error - unmatched '\"':\n\
                 │ Input: {}\n\
                 │        {}\n\
                 │ String literal is missing a closing double quote.",
                input,
                pointer_at(pos)
            )
        }
        Err::MissingOperatorOutsideOfBrace => {
            format!(
                "Syntax error:\n\
                 │ Input: {}\n\
                 │ Missing operator. Perhaps you meant to use '*' for multiplication?\n\
                 │ Example: '4(5)' should be '4 * (5)' or '4 * 5'",
                input
            )
        }
        Err::UnmatchedPartialToken { first, second } => {
            let second_str = second
                .as_ref()
                .map(|s| format!("{:?}", s))
                .unwrap_or_else(|| "end of input".to_string());
            format!(
                "Syntax error - incomplete token:\n\
                 │ Input: {}\n\
                 │ Found incomplete token '{:?}' followed by {}.\n\
                 │ Hint: Check for stray characters like '=' or incomplete operators.",
                input, first, second_str
            )
        }
        Err::AdditionError { augend, addend } => {
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot add {} + {}\n\
                 │ Hint: Ensure both operands are compatible numeric types.",
                input, augend, addend
            )
        }
        Err::SubtractionError {
            minuend,
            subtrahend,
        } => {
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot subtract {} - {}\n\
                 │ Hint: Ensure both operands are compatible numeric types.",
                input, minuend, subtrahend
            )
        }
        Err::NegationError { argument } => {
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot negate {}\n\
                 │ Hint: Negation only works on numeric values.",
                input, argument
            )
        }
        Err::MultiplicationError {
            multiplicand,
            multiplier,
        } => {
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot multiply {} * {}\n\
                 │ Hint: Ensure both operands are compatible numeric types.",
                input, multiplicand, multiplier
            )
        }
        Err::DivisionError { dividend, divisor } => {
            let is_zero =
                matches!(divisor, Val::Int(0)) || matches!(divisor, Val::Float(f) if *f == 0.0);
            let hint = if is_zero {
                "Division by zero is undefined."
            } else {
                "Ensure both operands are compatible numeric types."
            };
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot divide {} / {}\n\
                 │ Hint: {}",
                input, dividend, divisor, hint
            )
        }
        Err::ModulationError { dividend, divisor } => {
            let is_zero =
                matches!(divisor, Val::Int(0)) || matches!(divisor, Val::Float(f) if *f == 0.0);
            let hint = if is_zero {
                "Modulo by zero is undefined."
            } else {
                "Ensure both operands are compatible numeric types."
            };
            format!(
                "Arithmetic error:\n\
                 │ Input: {}\n\
                 │ Cannot compute {} % {}\n\
                 │ Hint: {}",
                input, dividend, divisor, hint
            )
        }
        Err::InvalidRegex { regex, message } => {
            format!(
                "Invalid regular expression:\n\
                 │ Input: {}\n\
                 │ Regex '{}' is invalid: {}",
                input, regex, message
            )
        }
        Err::ContextNotMutable => {
            format!(
                "Context error:\n\
                 │ Input: {}\n\
                 │ Cannot modify values in a read-only context.",
                input
            )
        }
        Err::IllegalEscapeSequence(seq) => {
            format!(
                "Syntax error - illegal escape sequence:\n\
                 │ Input: {}\n\
                 │ '{}' is not a valid escape sequence.\n\
                 │ Valid escapes: \\n, \\t, \\r, \\\\, \\\"",
                input, seq
            )
        }
        Err::OutOfBoundsAccess => {
            format!(
                "Index error:\n\
                 │ Input: {}\n\
                 │ Attempted to access an element outside valid bounds.",
                input
            )
        }
        Err::CustomMessage(msg) => {
            format!(
                "Error:\n\
                 │ Input: {}\n\
                 │ {}",
                input, msg
            )
        }
        // Catch-all for any other errors
        _ => {
            format!(
                "Error:\n\
                 │ Input: {}\n\
                 │ {}",
                input, err
            )
        }
    }
}

/// Get a human-readable type name for a value
fn value_type_name(val: &Val) -> &'static str {
    match val {
        Val::String(_) => "string",
        Val::Int(_) => "integer",
        Val::Float(_) => "float",
        Val::Boolean(_) => "boolean",
        Val::Tuple(_) => "tuple",
        Val::Empty => "empty",
    }
}

/// Find the position of an identifier in the input and create a pointer string
fn find_identifier_position(input: &str, name: &str) -> String {
    if let Some(pos) = input.find(name) {
        let spaces = " ".repeat(pos);
        let arrows = "^".repeat(name.len());
        format!("{}{}", spaces, arrows)
    } else {
        String::new()
    }
}

/// Create a pointer string at a specific position
fn pointer_at(pos: Option<usize>) -> String {
    match pos {
        Some(p) if p > 0 => format!("{}^", " ".repeat(p - 1)),
        Some(_) => "^".to_string(),
        None => String::new(),
    }
}

/// Suggest a similar function name for typos
fn suggest_function(name: &str) -> Option<&'static str> {
    const BUILTINS: &[&str] = &[
        "sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "exp", "ln",
        "log10", "log2", "abs", "floor", "ceil", "round", "pow", "min", "max",
    ];

    let name_lower = name.to_lowercase();

    // Check for exact match (case-insensitive)
    for &builtin in BUILTINS {
        if builtin == name_lower {
            return Some(builtin);
        }
    }

    // Check for similar names (simple edit distance)
    BUILTINS
        .iter()
        .find(|&&builtin| is_similar(&name_lower, builtin))
        .copied()
        .map(|v| v as _)
}

/// Simple similarity check (one character difference)
fn is_similar(a: &str, b: &str) -> bool {
    if a.len().abs_diff(b.len()) > 1 {
        return false;
    }

    let a_chars: Vec<_> = a.chars().collect();
    let b_chars: Vec<_> = b.chars().collect();

    let mut differences = 0;
    let mut i = 0;
    let mut j = 0;

    while i < a_chars.len() && j < b_chars.len() {
        if a_chars[i] != b_chars[j] {
            differences += 1;
            if differences > 1 {
                return false;
            }
            // Handle insertion/deletion
            if a_chars.len() > b_chars.len() {
                i += 1;
                continue;
            } else if a_chars.len() < b_chars.len() {
                j += 1;
                continue;
            }
        }
        i += 1;
        j += 1;
    }

    differences + (a_chars.len() - i) + (b_chars.len() - j) <= 1
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() > 1 {
        let first_arg = &args[1];
        match first_arg.as_str() {
            "--help" | "-h" | "help" => {
                eprintln!("Usage: fascia [bench]");
                std::process::exit(0);
            }
            "--version" | "-v" => {
                println!("Fascia Calculator REPL v0.1.0");
                std::process::exit(0);
            }
            "bench" => {} // Valid argument, handled below
            _ if args.len() > 2 => {
                eprintln!("Usage: fascia [bench]");
                std::process::exit(1);
            }
            _ => {} // Other single arguments will be treated as expressions if not handled
        }
    }

    // True for bench false for no bench
    let bench_mode = args.len() == 2 && args[1] == "bench";
    println!("╔════════════════════════════════════════════════════════════╗");
    println!("║              Fascia Calculator REPL v0.1.0                 ║");
    println!("║         Type 'help' for commands, 'quit' to exit           ║");
    println!("╚════════════════════════════════════════════════════════════╝");
    println!();

    let mut calculator = Calculator::new();

    loop {
        print!(">>> ");
        if io::stdout().flush().is_err() {
            continue;
        }

        let input = match read_line() {
            Some(line) => line,
            None => {
                println!("\nGoodbye!");
                break;
            }
        };

        if !calculator.process_input(&input, bench_mode) {
            println!("Goodbye!");
            break;
        }
    }
}
