/*!
 * Execution Runner Module - Nyash File and Mode Execution Coordinator
 *
 * This module handles all execution logic, backend selection, and mode coordination,
 * separated from CLI parsing and the main entry point.
 */

use nyash_rust::cli::CliConfig;
// prune heavy unused imports here; modules import what they need locally
// pruned unused runtime imports in this module

#[cfg(feature = "wasm-backend")]
use nyash_rust::backend::{aot::AotBackend, wasm::WasmBackend};

#[cfg(feature = "llvm-inkwell-legacy")]
use nyash_rust::backend::llvm_compile_and_execute;
use std::{fs, process};
mod box_index;
mod build;
pub(crate) mod child_env;
mod cli_directives;
mod demos;
mod dispatch;
pub mod json_v0_bridge;
mod json_v1_bridge;
pub mod mir_json {
    pub mod common;
}
pub mod core_executor;
pub mod hv1_inline;
pub mod mir_json_emit;
mod mir_json_v0;
pub mod modes;
mod pipe_io;
mod pipeline;
mod plugins;
pub(crate) mod repl; // Phase 288.1: Made pub(crate) for ExternCall bridge access  // Phase 288: REPL module
mod selfhost;
mod stage1_bridge;
mod tasks;
mod trace;

// v2 plugin system imports
use nyash_rust::runner_plugin_init;
use nyash_rust::runtime;
// use std::path::PathBuf; // not used in current runner

/// Resolve a using target according to priority: modules > relative > using-paths
/// Returns Ok(resolved_path_or_token). On strict mode, ambiguous matches cause error.
// use pipeline::resolve_using_target; // resolved within helpers; avoid unused warning

/// Main execution coordinator
pub struct NyashRunner {
    config: CliConfig,
}

/// Minimal task runner: read hako.toml (preferred) or nyash.toml [env]/[tasks], run the named task via shell
use tasks::run_named_task;

#[cfg(not(feature = "jit-direct-only"))]
impl NyashRunner {
    /// Create a new runner with the given configuration
    pub fn new(config: CliConfig) -> Self {
        // Phase 112: Ring0Context 初期化（グローバル、一度だけ）
        // RuntimeProfile に応じた Ring0Context を構築
        // OnceLock により、複数回呼ばれても最初の一度だけ初期化される
        let _ = runtime::ring0::GLOBAL_RING0.get_or_init(|| {
            let profile = runtime::RuntimeProfile::from_env();
            std::sync::Arc::new(runtime::ring0::Ring0Registry::build(profile))
        });

        Self {
            config,
        }
    }

    /// Run Nyash based on the configuration
    pub fn run(&self) {
        // New behavior-preserving delegator
        self.run_refactored();
    }

    // init_bid_plugins moved to runner_plugin_init.rs

    /// Execute file-based mode with backend selection
    pub(crate) fn run_file(&self, filename: &str) {
        dispatch::execute_file_with_backend(self, filename);
    }

    /// Minimal AOT build pipeline driven by hako.toml/nyash.toml (mvp)
    fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> {
        build::run_build_mvp_impl(self, cfg_path)
    }

}

#[cfg(not(feature = "jit-direct-only"))]
impl NyashRunner {
    /// New behavior-preserving refactor of run(): structured into smaller helpers
    fn run_refactored(&self) {
        // Early: macro child
        if let Some(ref macro_file) = self.config.macro_expand_child {
            crate::runner::modes::macro_child::run_macro_child(macro_file);
            return;
        }
        // Phase 288 P1: REPL mode
        if self.config.repl {
            repl::run_repl(self.config.clone());  // never returns
        }
        let groups = self.config.as_groups();

        // CLI mode trace: show backend/file/args when emit-mir trace is enabled
        if std::env::var("NYASH_EMIT_MIR_TRACE").ok().as_deref() == Some("1") {
            let backend = &groups.backend.backend;
            let file = groups.input.file.as_deref().unwrap_or("<none>");
            let args = std::env::args().skip(1).collect::<Vec<_>>().join(" ");
            eprintln!("[cli] mode={} file={} args={}", backend, file, args);
        }

        let skip_stage1_stub = groups.emit.hako_emit_program_json || groups.emit.hako_emit_mir_json;
        if !skip_stage1_stub {
            if let Some(code) = self.maybe_run_stage1_cli_stub(&groups) {
                std::process::exit(code);
            }
        }
        // Early: direct MIR JSON execution (no source file). Experimental diagnostics/exec.
        if let Some(path) = groups.parser.mir_json_file.as_ref() {
            // Phase 90-A: fs 系移行
            let ring0 = crate::runtime::ring0::get_global_ring0();
            match ring0.fs.read_to_string(std::path::Path::new(path)) {
                Ok(text) => match crate::runner::json_v1_bridge::try_parse_v1_to_module(&text) {
                    Ok(Some(module)) => {
                        let rc = self.execute_mir_module_quiet_exit(&module);
                        std::process::exit(rc);
                    }
                    Ok(None) => {
                        if text.contains("\"functions\"") && text.contains("\"blocks\"") {
                            match crate::runner::mir_json_v0::parse_mir_v0_to_module(&text) {
                                Ok(module) => {
                                    let rc = self.execute_mir_module_quiet_exit(&module);
                                    std::process::exit(rc);
                                }
                                Err(e) => {
                                    eprintln!("❌ MIR JSON v0 parse error: {}", e);
                                    std::process::exit(1);
                                }
                            }
                        } else {
                            eprintln!("❌ MIR JSON invalid or unsupported shape: {}", path);
                            std::process::exit(1);
                        }
                    }
                    Err(e) => {
                        eprintln!("❌ MIR JSON parse error (v1): {}", e);
                        std::process::exit(1);
                    }
                },
                Err(e) => {
                    eprintln!("❌ Error reading MIR JSON {}: {}", path, e);
                    std::process::exit(1);
                }
            }
        }
        // Early: build
        if let Some(cfg_path) = groups.build.path.clone() {
            if let Err(e) = self.run_build_mvp(&cfg_path) {
                eprintln!("❌ build error: {}", e);
                std::process::exit(1);
            }
            return;
        }
        // Emit Program(JSON v0) and exit
        if let Some(path) = groups.emit.emit_program_json.as_ref() {
            // Prefer Stage-1/.hako route when requested via hako-* flags or env
            let use_hako = groups.emit.hako_emit_program_json
                || crate::config::env::stage1::emit_program_json()
                || crate::config::env::stage1::enabled();
            if use_hako {
                if let Err(e) = self.emit_program_json_v0(&groups, path) {
                    eprintln!("❌ emit-program-json error: {}", e);
                    std::process::exit(1);
                } else {
                    println!("Program JSON written: {}", path);
                    std::process::exit(0);
                }
            } else if let Some(file) = groups.input.file.as_ref() {
                // Phase 90-A: fs 系移行
                let ring0 = crate::runtime::ring0::get_global_ring0();
                match ring0.fs.read_to_string(std::path::Path::new(file)) {
                    Ok(code) => match crate::parser::NyashParser::parse_from_string(&code) {
                        Ok(ast) => {
                            let prog = crate::r#macro::ast_json::ast_to_json(&ast);
                            let out_path = std::path::Path::new(path);
                            if let Err(e) = std::fs::write(out_path, prog.to_string()) {
                                eprintln!("❌ emit-program-json write error: {}", e);
                                std::process::exit(1);
                            }
                            println!("Program JSON written: {}", out_path.display());
                            std::process::exit(0);
                        }
                        Err(e) => {
                            crate::runner::modes::common_util::diag::print_parse_error_with_context(
                                file, &code, &e,
                            );
                            std::process::exit(1);
                        }
                    },
                    Err(e) => {
                        eprintln!("❌ Error reading file {}: {}", file, e);
                        std::process::exit(1);
                    }
                }
            } else {
                eprintln!("❌ --emit-program-json requires an input file");
                std::process::exit(1);
            }
        }
        // Preprocess usings and directives (includes dep-tree log)
        self.preprocess_usings_and_directives(&groups);
        // JSON v0 bridge
        if self.try_run_json_v0_pipe() {
            return;
        }
        // Named task
        if let Some(task) = groups.run_task.clone() {
            if let Err(e) = run_named_task(&task) {
                eprintln!("❌ Task error: {}", e);
                process::exit(1);
            }
            return;
        }
        // Common env + runtime/plugins
        self.apply_common_env(&groups);
        self.init_runtime_and_plugins(&groups);
        // Backend config + policy
        self.configure_backend(&groups);
        self.enforce_runtime_jit_policy(&groups);
        // Benchmark
        if self.maybe_run_benchmark(&groups) {
            return;
        }
        // Dispatch
        if std::env::var("NYASH_VM_ROUTE_TRACE").ok().as_deref() == Some("1") {
            let backend = &groups.backend.backend;
            let file = groups.input.file.as_deref().unwrap_or("<none>");
            eprintln!("[vm-route] pre-dispatch backend={} file={}", backend, file);
        }
        self.dispatch_entry(&groups);
    }

    // ---- Helpers (extracted from original run) ----

    fn preprocess_usings_and_directives(&self, groups: &crate::cli::CliGroups) {
        use pipeline::resolve_using_target;
        // Initialize UsingContext (defaults + nyash.toml + env)
        let mut using_ctx = self.init_using_context();
        // Collect CLI --using SPEC into (target, alias)
        let mut pending_using: Vec<(String, Option<String>)> = Vec::new();
        for spec in &groups.input.cli_usings {
            let s = spec.trim();
            if s.is_empty() {
                continue;
            }
            let (target, alias) = if let Some(pos) = s.find(" as ") {
                (
                    s[..pos].trim().to_string(),
                    Some(s[pos + 4..].trim().to_string()),
                )
            } else {
                (s.to_string(), None)
            };
            let is_path = crate::runner::modes::common_util::resolve::path_util::is_using_target_path_original(&target);
            if is_path {
                let path = target.trim_matches('"').to_string();
                let name = alias.clone().unwrap_or_else(|| {
                    std::path::Path::new(&path)
                        .file_stem()
                        .and_then(|s| s.to_str())
                        .unwrap_or("module")
                        .to_string()
                });
                pending_using.push((name, Some(path)));
            } else {
                pending_using.push((target, alias));
            }
        }
        // Apply pending modules (from context) to registry as StringBox
        for (ns, path) in using_ctx.pending_modules.iter() {
            let sb = crate::box_trait::StringBox::new(path.clone());
            crate::runtime::modules_registry::set(ns.clone(), Box::new(sb));
        }
        // Optional dependency tree bridge (log-only)
        if let Ok(dep_path) = std::env::var("NYASH_DEPS_JSON") {
            // Phase 90-A: fs 系移行
            let ring0 = crate::runtime::ring0::get_global_ring0();
            match ring0.fs.read_to_string(std::path::Path::new(&dep_path)) {
                Ok(s) => {
                    let bytes = s.as_bytes().len();
                    let mut root_info = String::new();
                    if let Ok(v) = serde_json::from_str::<serde_json::Value>(&s) {
                        if let Some(r) = v.get("root_path").and_then(|x| x.as_str()) {
                            root_info = format!(" root='{}'", r);
                        }
                    }
                    crate::cli_v!(
                        "[deps] loaded {} bytes from{} {}",
                        bytes,
                        if root_info.is_empty() { "" } else { ":" },
                        root_info
                    );
                }
                Err(e) => {
                    crate::cli_v!("[deps] read error: {}", e);
                }
            }
        }
        // If a file is provided, apply script-level directives and late using/env merges
        if let Some(ref filename) = groups.input.file {
            if let Ok(code) = fs::read_to_string(filename) {
                // Apply directives and lint
                let strict_fields =
                    std::env::var("NYASH_FIELDS_TOP_STRICT").ok().as_deref() == Some("1");
                if let Err(e) = cli_directives::apply_cli_directives_from_source(
                    &code,
                    strict_fields,
                    groups.debug.cli_verbose,
                ) {
                    eprintln!("❌ Lint/Directive error: {}", e);
                    std::process::exit(1);
                }
                // Late env overrides (paths/modules)
                if let Ok(paths) = std::env::var("NYASH_USING_PATH") {
                    for p in paths.split(':') {
                        let p = p.trim();
                        if !p.is_empty() {
                            using_ctx.using_paths.push(p.to_string());
                        }
                    }
                }
                if let Ok(mods) = std::env::var("NYASH_MODULES") {
                    for ent in mods.split(',') {
                        if let Some((k, v)) = ent.split_once('=') {
                            let k = k.trim();
                            let v = v.trim();
                            if !k.is_empty() && !v.is_empty() {
                                using_ctx
                                    .pending_modules
                                    .push((k.to_string(), v.to_string()));
                            }
                        }
                    }
                }
                // Re-apply pending modules in case env added more (idempotent)
                for (ns, path) in using_ctx.pending_modules.iter() {
                    let sb = nyash_rust::box_trait::StringBox::new(path.clone());
                    nyash_rust::runtime::modules_registry::set(ns.clone(), Box::new(sb));
                }
                // Resolve CLI --using entries against context and register values (with aliasing)
                let strict = std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1");
                let verbose = crate::config::env::cli_verbose();
                let ctx = std::path::Path::new(filename).parent();
                for (ns, alias) in pending_using.iter() {
                    let value = match resolve_using_target(
                        ns,
                        false,
                        &using_ctx.pending_modules,
                        &using_ctx.using_paths,
                        &using_ctx.aliases,
                        &using_ctx.packages,
                        ctx,
                        strict,
                        verbose,
                    ) {
                        Ok(v) => v,
                        Err(e) => {
                            eprintln!("❌ using: {}", e);
                            std::process::exit(1);
                        }
                    };
                    let sb = nyash_rust::box_trait::StringBox::new(value.clone());
                    nyash_rust::runtime::modules_registry::set(ns.clone(), Box::new(sb));
                    if let Some(a) = alias {
                        let sb2 = nyash_rust::box_trait::StringBox::new(value);
                        nyash_rust::runtime::modules_registry::set(a.clone(), Box::new(sb2));
                    }
                }
            }
        }
    }

    /// Apply early environment toggles that affect CLI behavior and VM stats.
    /// Side effects: sets `NYASH_CLI_VERBOSE`, `NYASH_GC_MODE` when specified by CLI groups.
    fn apply_common_env(&self, groups: &crate::cli::CliGroups) {
        if groups.debug.cli_verbose {
            std::env::set_var("NYASH_CLI_VERBOSE", "1");
        }
        if let Some(ref m) = groups.gc_mode {
            if !m.trim().is_empty() {
                std::env::set_var("NYASH_GC_MODE", m);
            }
        }
    }

    // init_runtime_and_plugins moved to runner/plugins.rs

    /// Configure backend knobs (VM) from CLI flags and env.
    /// JIT configuration removed with JIT/Cranelift archival.
    fn configure_backend(&self, groups: &crate::cli::CliGroups) {
        if groups.backend.vm_stats {
            std::env::set_var("NYASH_VM_STATS", "1");
        }
        if groups.backend.vm_stats_json {
            std::env::set_var("NYASH_VM_STATS_JSON", "1");
        }
        // JIT configuration removed - archived to archive/jit-cranelift/
    }

    /// JIT runtime policy enforcement removed with JIT/Cranelift archival.
    fn enforce_runtime_jit_policy(&self, _groups: &crate::cli::CliGroups) {
        // JIT policy enforcement removed - archived to archive/jit-cranelift/
    }

    /// Optionally run the benchmark suite and exit, depending on CLI flags.
    /// Returns true when a benchmark run occurred.
    fn maybe_run_benchmark(&self, groups: &crate::cli::CliGroups) -> bool {
        if groups.benchmark {
            println!("📊 Nyash Performance Benchmark Suite");
            println!("====================================");
            println!("Running {} iterations per test...", groups.iterations);
            println!();
            // VM-legacy removed - benchmark mode no longer available
            eprintln!(
                "❌ Benchmark mode removed with vm-legacy. Use regular execution modes instead."
            );
            std::process::exit(1);
        }
        false
    }

    /// Final dispatch to selected execution mode (file/JIT-direct or demos).
    fn dispatch_entry(&self, groups: &crate::cli::CliGroups) {
        if let Some(ref filename) = groups.input.file {
            if groups.backend.jit.direct {
                self.run_file_jit_direct(filename);
                return;
            }
            // Optional route trace before delegating to backend dispatcher
            if std::env::var("NYASH_VM_ROUTE_TRACE").ok().as_deref() == Some("1") {
                eprintln!(
                    "[vm-route] pre-dispatch backend={} file={}",
                    groups.backend.backend, filename
                );
            }
            self.run_file(filename);
        } else {
            demos::run_all_demos();
        }
    }
}

impl NyashRunner {
    /// Run a file through independent JIT engine (no VM execute loop)
    /// ARCHIVED: JIT/Cranelift functionality disabled for Phase 15
    fn run_file_jit_direct(&self, filename: &str) {
        eprintln!("❌ JIT-direct mode is archived for Phase 15. JIT/Cranelift moved to archive/jit-cranelift/");
        eprintln!("   Use VM backend instead: nyash {}", filename);
        eprintln!("   Or use LLVM backend: nyash --backend llvm {}", filename);
        std::process::exit(1);
    }
}
// moved to demos.rs

// moved to demos.rs

// moved to demos.rs

// moved to demos.rs

// moved to demos.rs

// moved to demos.rs
