/*!
 * External Call Handling
 *
 * Manages env.* methods and external interface calls
 * Provides bridge to host environment functionality
 */

use crate::mir::{Effect, EffectMask};

/// Table-like spec for env.* methods
/// Returns (iface_name, method_name, effects, returns_value)
pub fn get_env_method_spec(
    iface: &str,
    method: &str,
) -> Option<(String, String, EffectMask, bool)> {
    match (iface, method) {
        // Future/async operations
        ("future", "delay") => Some((
            "env.future".to_string(),
            "delay".to_string(),
            EffectMask::READ.add(Effect::Io),
            true,
        )),
        ("future", "spawn") => Some((
            "env.future".to_string(),
            "spawn".to_string(),
            EffectMask::IO,
            true,
        )),

        // Task management
        ("task", "currentToken") => Some((
            "env.task".to_string(),
            "currentToken".to_string(),
            EffectMask::READ,
            true,
        )),
        ("task", "cancelCurrent") => Some((
            "env.task".to_string(),
            "cancelCurrent".to_string(),
            EffectMask::IO,
            false,
        )),

        // Console I/O
        ("console", "log") => Some((
            "env.console".to_string(),
            "log".to_string(),
            EffectMask::IO,
            false,
        )),
        ("console", "readLine") => Some((
            "env.console".to_string(),
            "readLine".to_string(),
            EffectMask::IO,
            true,
        )),
        ("console", "error") => Some((
            "env.console".to_string(),
            "error".to_string(),
            EffectMask::IO,
            false,
        )),

        // Canvas operations
        ("canvas", m) if matches!(m, "fillRect" | "fillText" | "clear") => Some((
            "env.canvas".to_string(),
            method.to_string(),
            EffectMask::IO,
            false,
        )),

        // File system
        ("fs", "readFile") => Some((
            "env.fs".to_string(),
            "readFile".to_string(),
            EffectMask::IO,
            true,
        )),
        ("fs", "writeFile") => Some((
            "env.fs".to_string(),
            "writeFile".to_string(),
            EffectMask::IO,
            false,
        )),
        ("fs", "exists") => Some((
            "env.fs".to_string(),
            "exists".to_string(),
            EffectMask::READ,
            true,
        )),

        // Network
        ("net", "fetch") => Some((
            "env.net".to_string(),
            "fetch".to_string(),
            EffectMask::IO,
            true,
        )),
        ("net", "listen") => Some((
            "env.net".to_string(),
            "listen".to_string(),
            EffectMask::IO,
            true,
        )),

        // Process/system
        ("process", "exit") => Some((
            "env.process".to_string(),
            "exit".to_string(),
            EffectMask::IO.add(Effect::Control),
            false,
        )),
        ("process", "argv") => Some((
            "env.process".to_string(),
            "argv".to_string(),
            EffectMask::READ,
            true,
        )),
        ("process", "env") => Some((
            "env.process".to_string(),
            "env".to_string(),
            EffectMask::READ,
            true,
        )),

        // Direct env access
        ("env", "get") => Some(("env".to_string(), "get".to_string(), EffectMask::READ, true)),
        ("env", "set") => Some(("env".to_string(), "set".to_string(), EffectMask::IO, false)),

        // Unknown
        _ => None,
    }
}

/// Parse external call name into interface and method
/// E.g., "nyash.builtin.print" -> ("nyash.builtin", "print")
pub fn parse_extern_name(name: &str) -> (String, String) {
    let parts: Vec<&str> = name.rsplitn(2, '.').collect();
    if parts.len() == 2 {
        (parts[1].to_string(), parts[0].to_string())
    } else {
        ("nyash".to_string(), name.to_string())
    }
}

/// Check if a name refers to an environment interface
#[allow(dead_code)]
pub fn is_env_interface(name: &str) -> bool {
    matches!(
        name,
        "env"
            | "env.console"
            | "env.fs"
            | "env.net"
            | "env.canvas"
            | "env.task"
            | "env.future"
            | "env.process"
    )
}

/// Determine effects for an external call
pub fn compute_extern_effects(iface: &str, method: &str) -> EffectMask {
    match (iface, method) {
        // Pure reads
        (_, m) if m.starts_with("get") || m == "argv" || m == "env" => EffectMask::READ,
        // Control flow changes
        (_, "exit") | (_, "panic") | (_, "throw") => EffectMask::IO.add(Effect::Control),
        // Memory allocation
        (_, m) if m.starts_with("new") || m.starts_with("create") => {
            EffectMask::IO.add(Effect::Alloc)
        }
        // Default to I/O
        _ => EffectMask::IO,
    }
}
