#!/usr/bin/env nu

# Rustelo Prerequisites Verification
# Verifies that all required tools are properly installed and working

def main [
    --verbose (-v)       # Show detailed version information
    --fix-path          # Attempt to fix PATH issues
    --format (-f): string = "human"  # Output format: human, json, yaml, toml
] {
    # Validate format parameter
    if $format not-in ["human", "json", "yaml", "toml"] {
        print $"Error: Invalid format '($format)'. Supported formats: human, json, yaml, toml"
        return
    }
    
    # Collect all system and prerequisite information
    let system_info = if $verbose or $format != "human" {
        collect_system_info
    } else {
        {}
    }
    
    let rust_status = collect_rust_info $verbose
    let node_status = collect_node_info $verbose  
    let nushell_status = collect_nushell_info $verbose
    let just_status = collect_just_info $verbose
    let additional_tools = collect_additional_tools_info $verbose
    
    # Compile results
    let prerequisites = {
        rust: $rust_status,
        node: $node_status,
        nushell: $nushell_status,
        just: $just_status
    }
    
    let all_required_ok = (
        $rust_status.installed and 
        $node_status.installed and 
        $nushell_status.installed and 
        $just_status.installed
    )
    
    let issues = (
        [$rust_status, $node_status, $nushell_status, $just_status] 
        | where not installed 
        | get issue
        | where $it != null
    )
    
    # Create comprehensive result object
    let result = {
        timestamp: (date now | format date '%Y-%m-%dT%H:%M:%S%.3fZ'),
        system: $system_info,
        prerequisites: $prerequisites,
        additional_tools: $additional_tools,
        summary: {
            all_prerequisites_met: $all_required_ok,
            total_issues: ($issues | length),
            issues: $issues
        }
    }
    
    # Output in requested format
    match $format {
        "human" => { output_human $result $verbose $fix_path },
        "json" => { $result | to json },
        "yaml" => { $result | to yaml },
        "toml" => { $result | to toml }
    }
}

# Data collection functions for structured output
def collect_system_info [] {
    let os_name = try { 
        let uname_s = (^uname -s | str trim)
        match $uname_s {
            "Darwin" => "macOS",
            "Linux" => "Linux", 
            "MINGW64_NT" => "Windows",
            _ => $uname_s
        }
    } catch { 
        try { (sys host | get name) } catch { "unknown" }
    }
    
    let arch = try {
        let uname_m = (^uname -m | str trim)
        match $uname_m {
            "arm64" => "Apple Silicon (ARM64)",
            "x86_64" => "Intel x64",
            "aarch64" => "ARM64",
            _ => $uname_m
        }
    } catch {
        try { (sys host | get cpu | first | get brand) } catch { "unknown" }
    }
    
    let kernel = try {
        (^uname -r | str trim)
    } catch {
        try { (sys host | get kernel_version) } catch { "unknown" }
    }
    
    let detailed_os = if ($os_name == "macOS") {
        let version = try { (^sw_vers -productVersion | str trim) } catch { "" }
        let name = try { (^sw_vers -productName | str trim) } catch { "" }
        if ($version != "" and $name != "") {
            $"($name) ($version)"
        } else {
            $os_name
        }
    } else {
        $os_name
    }
    
    {
        os: $detailed_os,
        arch: $arch,
        kernel: $kernel,
        shell: ($env.SHELL? | default 'unknown')
    }
}

def collect_rust_info [verbose: bool] {
    if (which rustc | is-not-empty) and (which cargo | is-not-empty) {
        let rustc_version = try { (rustc --version | str trim) } catch { "unknown" }
        let cargo_version = try { (cargo --version | str trim) } catch { "unknown" }
        let toolchain = try { (rustup show active-toolchain | str trim) } catch { "unknown" }
        
        {
            installed: true,
            rustc_version: $rustc_version,
            cargo_version: $cargo_version,
            toolchain: $toolchain,
            issue: null
        }
    } else {
        {
            installed: false,
            rustc_version: null,
            cargo_version: null,
            toolchain: null,
            issue: "Rust compiler (rustc) and Cargo not found. Install from https://rustup.rs/"
        }
    }
}

def collect_node_info [verbose: bool] {
    let node_ok = (which node | is-not-empty)
    let pnpm_ok = (which pnpm | is-not-empty)
    let npm_ok = (which npm | is-not-empty)
    
    let node_version = if $node_ok { try { (node --version | str trim) } catch { null } } else { null }
    let pnpm_version = if $pnpm_ok { try { (pnpm --version | str trim) } catch { null } } else { null }
    let npm_version = if $npm_ok { try { (npm --version | str trim) } catch { null } } else { null }
    
    if $node_ok and $pnpm_ok {
        {
            installed: true,
            node_version: $node_version,
            pnpm_version: $pnpm_version,
            npm_version: $npm_version,
            issue: null
        }
    } else if $node_ok and not $pnpm_ok {
        {
            installed: false,
            node_version: $node_version,
            pnpm_version: null,
            npm_version: $npm_version,
            issue: "pnpm package manager not found. Install with: npm install -g pnpm"
        }
    } else {
        {
            installed: false,
            node_version: null,
            pnpm_version: null,
            npm_version: null,
            issue: "Node.js and pnpm not found. Install Node.js from https://nodejs.org/ then run: npm install -g pnpm"
        }
    }
}

def collect_nushell_info [verbose: bool] {
    if (which nu | is-not-empty) {
        let version = try { (nu --version | lines | first | str trim) } catch { "unknown" }
        let features = try { (nu -c "version | get features" | str join ", ") } catch { "unknown" }
        
        {
            installed: true,
            version: $version,
            features: $features,
            current_shell: ($env.SHELL? | default "unknown"),
            issue: null
        }
    } else {
        {
            installed: false,
            version: null,
            features: null,
            current_shell: ($env.SHELL? | default "unknown"),
            issue: "Nushell shell not found. Install from https://github.com/nushell/nushell/releases or via package manager"
        }
    }
}

def collect_just_info [verbose: bool] {
    if (which just | is-not-empty) {
        let version = try { (just --version | str trim) } catch { "unknown" }
        let justfile_exists = ("justfile" | path exists) or ("Justfile" | path exists)
        
        {
            installed: true,
            version: $version,
            justfile_found: $justfile_exists,
            issue: null
        }
    } else {
        {
            installed: false,
            version: null,
            justfile_found: false,
            issue: "Just command runner not found. Install with: cargo install just"
        }
    }
}

def collect_additional_tools_info [verbose: bool] {
    let tools = [
        {
            name: "git",
            installed: (which git | is-not-empty),
            version: (if (which git | is-not-empty) { try { (git --version | str replace "git version " "") } catch { "unknown" } } else { null })
        },
        {
            name: "sqlite",
            installed: (which sqlite3 | is-not-empty),
            version: (if (which sqlite3 | is-not-empty) { try { (sqlite3 --version | split row " " | first) } catch { "unknown" } } else { null })
        },
        {
            name: "docker",
            installed: (which docker | is-not-empty),
            version: (if (which docker | is-not-empty) { try { (docker --version | str replace "Docker version " "" | split row "," | first) } catch { "unknown" } } else { null })
        },
        {
            name: "vscode",
            installed: ((which code | is-not-empty) or ("/Applications/Visual Studio Code.app" | path exists)),
            version: (if (which code | is-not-empty) { 
                try { (code --version | lines | first) } catch { "available" } 
            } else if ("/Applications/Visual Studio Code.app" | path exists) { 
                "installed (app bundle)"
            } else { 
                null 
            })
        },
        {
            name: "zed",
            installed: ((which zed | is-not-empty) or ("/Applications/Zed.app" | path exists)),
            version: (if (which zed | is-not-empty) { 
                try { (zed --version | str trim) } catch { "available" } 
            } else if ("/Applications/Zed.app" | path exists) { 
                "installed (app bundle)"
            } else { 
                null 
            })
        },
        {
            name: "claude-code",
            installed: ((which claude-code | is-not-empty) or (which claude | is-not-empty) or ("/Applications/Claude.app" | path exists)),
            version: (if (which claude-code | is-not-empty) { 
                try { (claude-code --version | str trim) } catch { "available" } 
            } else if (which claude | is-not-empty) {
                try { (claude --version | str trim) } catch { "available" }
            } else if ("/Applications/Claude.app" | path exists) { 
                "installed (app bundle)"
            } else { 
                null 
            })
        },
        {
            name: "neovim",
            installed: (which nvim | is-not-empty),
            version: (if (which nvim | is-not-empty) { try { (nvim --version | lines | first | str replace "NVIM " "") } catch { "available" } } else { null })
        },
        {
            name: "gemini",
            installed: ((which gemini | is-not-empty) or ("/Applications/Gemini 2- The Duplicate Finder.app" | path exists)),
            version: (if (which gemini | is-not-empty) { 
                try { (gemini --version | str trim) } catch { "available" } 
            } else if ("/Applications/Gemini 2- The Duplicate Finder.app" | path exists) { 
                "installed (app bundle)"
            } else { null })
        },
        {
            name: "codex",
            installed: (which codex | is-not-empty),
            version: (if (which codex | is-not-empty) { try { (codex --version | str trim) } catch { "available" } } else { null })
        }
    ]
    
    $tools
}

def output_human [result: record, verbose: bool, fix_path: bool] {
    print "🔍 Verifying Rustelo Prerequisites..."
    print ""
    
    # Show system information if verbose
    if $verbose and ($result.system | is-not-empty) {
        print ""
        print "💻 System Information:"
        print $"   OS: ($result.system.os)"
        print $"   Arch: ($result.system.arch)"  
        print $"   Kernel: ($result.system.kernel)"
        print $"   Shell: ($result.system.shell)"
        print ""
    }
    
    # Show prerequisites
    let prereqs = $result.prerequisites
    
    if $prereqs.rust.installed {
        print $"✅ Rust: ($prereqs.rust.rustc_version)"
        if $verbose {
            print $"   Cargo: ($prereqs.rust.cargo_version)"
            print $"   Toolchain: ($prereqs.rust.toolchain)"
        }
    } else {
        print "❌ Rust: Not found"
    }
    
    if $prereqs.node.installed {
        print $"✅ Node.js: ($prereqs.node.node_version)"
        print $"✅ pnpm: ($prereqs.node.pnpm_version)"
        if $verbose and ($prereqs.node.npm_version != null) {
            print $"   npm: ($prereqs.node.npm_version)"
        }
    } else if ($prereqs.node.node_version != null) {
        print $"✅ Node.js: ($prereqs.node.node_version)"
        print "❌ pnpm: Not found"
    } else {
        print "❌ Node.js: Not found"
        print "❌ pnpm: Not found"
    }
    
    if $prereqs.nushell.installed {
        print $"✅ Nushell: ($prereqs.nushell.version)"
        if $verbose {
            print $"   Current shell: ($prereqs.nushell.current_shell)"
            print $"   Features: ($prereqs.nushell.features)"
        }
    } else {
        print "❌ Nushell: Not found"
    }
    
    if $prereqs.just.installed {
        print $"✅ Just: ($prereqs.just.version)"
        if $verbose and $prereqs.just.justfile_found {
            print "   ✅ justfile found in current directory"
        } else if $verbose {
            print "   ⚠️  No justfile found in current directory"
        }
    } else {
        print "❌ Just: Not found"
    }
    
    # Show additional tools
    print ""
    print "🔧 Additional Development Tools:"
    for tool in $result.additional_tools {
        if $tool.installed {
            match $tool.name {
                "vscode" => { print $"✅ VS Code: ($tool.version)" },
                "zed" => { print $"✅ Zed Editor: ($tool.version)" },
                "claude-code" => { print $"✅ Claude Code: ($tool.version)" },
                "neovim" => { print $"✅ Neovim: ($tool.version)" },
                "mvps" => { print $"✅ MVPS: ($tool.version)" },
                _ => { print $"✅ ($tool.name | str title-case): ($tool.version)" }
            }
        } else {
            match $tool.name {
                "git" => { print "⚠️  Git: Not found (recommended for version control)" },
                "sqlite" => { print "⚠️  SQLite: Not found (useful for local database development)" },
                "docker" => { print "ℹ️  Docker: Not found (optional, for containerized deployment)" },
                "vscode" => { print "ℹ️  VS Code: Not found (popular code editor)" },
                "zed" => { print "ℹ️  Zed Editor: Not found (modern collaborative editor)" },
                "claude-code" => { print "ℹ️  Claude Code: Not found (AI-powered coding assistant)" },
                "neovim" => { print "ℹ️  Neovim: Not found (vim-based editor)" },
                "mvps" => { print "ℹ️  MVPS: Not found (development tool)" }
            }
        }
    }
    
    print ""
    
    if $result.summary.all_prerequisites_met {
        print "✅ All prerequisites are properly installed!"
        print ""
        print "🚀 You're ready to create Rustelo projects:"
        print "   rustelo new my-website"
        print "   cd my-website"
        print "   just dev"
        print ""
    } else {
        print "❌ Some prerequisites are missing or have issues:"
        print ""
        for issue in $result.summary.issues {
            print $"   • ($issue)"
        }
        print ""
        print "🔧 To fix these issues:"
        print "   nu scripts/install-prerequisites.nu"
        print ""
        if $fix_path {
            attempt_path_fix
        }
    }
}

def check_rust [verbose: bool] {
    if (which rustc | is-not-empty) and (which cargo | is-not-empty) {
        let rustc_version = (rustc --version | str trim)
        let cargo_version = (cargo --version | str trim)
        
        print $"✅ Rust: ($rustc_version)"
        if $verbose {
            print $"   Cargo: ($cargo_version)"
            print $"   Toolchain: (rustup show active-toolchain | str trim)"
        }
        
        { ok: true, issue: null }
    } else {
        print "❌ Rust: Not found"
        { ok: false, issue: "Rust compiler (rustc) and Cargo not found. Install from https://rustup.rs/" }
    }
}

def check_node [verbose: bool] {
    let node_ok = (which node | is-not-empty)
    let pnpm_ok = (which pnpm | is-not-empty)
    
    if $node_ok and $pnpm_ok {
        let node_version = (node --version | str trim)
        let pnpm_version = (pnpm --version | str trim)
        
        print $"✅ Node.js: ($node_version)"
        print $"✅ pnpm: ($pnpm_version)"
        
        if $verbose {
            let npm_version = if (which npm | is-not-empty) { (npm --version | str trim) } else { "not found" }
            print $"   npm: ($npm_version)"
        }
        
        { ok: true, issue: null }
    } else if $node_ok and not $pnpm_ok {
        let node_version = (node --version | str trim)
        print $"✅ Node.js: ($node_version)"
        print "❌ pnpm: Not found"
        { ok: false, issue: "pnpm package manager not found. Install with: npm install -g pnpm" }
    } else {
        print "❌ Node.js: Not found"
        print "❌ pnpm: Not found"  
        { ok: false, issue: "Node.js and pnpm not found. Install Node.js from https://nodejs.org/ then run: npm install -g pnpm" }
    }
}

def check_nushell [verbose: bool] {
    if (which nu | is-not-empty) {
        let version = (nu --version | lines | first | str trim)
        print $"✅ Nushell: ($version)"
        
        if $verbose {
            # Check if current shell is nushell
            let current_shell = ($env.SHELL? | default "unknown")
            print $"   Current shell: ($current_shell)"
            
            # Check nushell features
            try {
                let features = (nu -c "version | get features" | str join ", ")
                print $"   Features: ($features)"
            } catch {
                print "   Features: Could not determine"
            }
        }
        
        { ok: true, issue: null }
    } else {
        print "❌ Nushell: Not found"
        { ok: false, issue: "Nushell shell not found. Install from https://github.com/nushell/nushell/releases or via package manager" }
    }
}

def check_just [verbose: bool] {
    if (which just | is-not-empty) {
        let version = (just --version | str trim)
        print $"✅ Just: ($version)"
        
        if $verbose {
            # Check if justfile exists in current directory
            if ("justfile" | path exists) {
                print "   ✅ justfile found in current directory"
            } else if ("Justfile" | path exists) {
                print "   ✅ Justfile found in current directory"
            } else {
                print "   ⚠️  No justfile found in current directory"
            }
        }
        
        { ok: true, issue: null }
    } else {
        print "❌ Just: Not found"
        { ok: false, issue: "Just command runner not found. Install with: cargo install just" }
    }
}

def check_additional_tools [verbose: bool] {
    print ""
    print "🔧 Additional Development Tools:"
    
    # Git
    if (which git | is-not-empty) {
        let version = (git --version | str replace "git version " "")
        print $"✅ Git: ($version)"
    } else {
        print "⚠️  Git: Not found (recommended for version control)"
    }
    
    # SQLite (useful for local development)
    if (which sqlite3 | is-not-empty) {
        let version = (sqlite3 --version | split row " " | first)
        print $"✅ SQLite: ($version)"
    } else {
        print "⚠️  SQLite: Not found (useful for local database development)"
    }
    
    # Docker (for containerized deployments)
    if (which docker | is-not-empty) {
        let version = (docker --version | str replace "Docker version " "" | split row "," | first)
        print $"✅ Docker: ($version)"
    } else {
        print "ℹ️  Docker: Not found (optional, for containerized deployment)"
    }
    
    # VS Code or other editors with Rust support
    if (which code | is-not-empty) {
        print "✅ VS Code: Available"
    } else if (which nvim | is-not-empty) {
        print "✅ Neovim: Available"  
    } else if (which vim | is-not-empty) {
        print "✅ Vim: Available"
    } else {
        print "ℹ️  Editor: Consider installing VS Code with rust-analyzer extension"
    }
}

def attempt_path_fix [] {
    print ""
    print "🔧 Attempting to fix PATH issues..."
    
    let home = $env.HOME
    let cargo_bin = $"($home)/.cargo/bin"
    let local_bin = "/usr/local/bin"
    
    # Check if cargo bin is in PATH
    if not ($env.PATH | split row ":" | any { |p| $p == $cargo_bin }) {
        print $"Adding ($cargo_bin) to PATH..."
        $env.PATH = ($env.PATH | split row ":" | append $cargo_bin | uniq)
    }
    
    # Check if local bin is in PATH  
    if not ($env.PATH | split row ":" | any { |p| $p == $local_bin }) {
        print $"Adding ($local_bin) to PATH..."
        $env.PATH = ($env.PATH | split row ":" | append $local_bin | uniq)
    }
    
    # Suggest shell configuration updates
    print ""
    print "💡 To make PATH changes permanent, add these lines to your shell config:"
    print ""
    
    let shell_config = match ($env.SHELL? | default "") {
        $path if ($path | str ends-with "zsh") => "~/.zshrc",
        $path if ($path | str ends-with "bash") => "~/.bashrc", 
        $path if ($path | str ends-with "fish") => "~/.config/fish/config.fish",
        _ => "~/.bashrc"
    }
    
    print $"   echo 'export PATH=\"$PATH:($cargo_bin):($local_bin)\"' >> ($shell_config)"
    print "   source ($shell_config)"
    print ""
}

# Show system information if verbose
def show_system_info [] {
    print ""
    print "💻 System Information:"
    
    # Get system info properly for different platforms
    let os_name = try { 
        let uname_s = (^uname -s | str trim)
        match $uname_s {
            "Darwin" => "macOS",
            "Linux" => "Linux", 
            "MINGW64_NT" => "Windows",
            _ => $uname_s
        }
    } catch { 
        try { (sys host | get name) } catch { "unknown" }
    }
    
    let arch = try {
        let uname_m = (^uname -m | str trim)
        match $uname_m {
            "arm64" => "Apple Silicon (ARM64)",
            "x86_64" => "Intel x64",
            "aarch64" => "ARM64",
            _ => $uname_m
        }
    } catch {
        try { (sys host | get cpu | first | get brand) } catch { "unknown" }
    }
    
    let kernel = try {
        (^uname -r | str trim)
    } catch {
        try { (sys host | get kernel_version) } catch { "unknown" }
    }
    
    # Get more detailed OS info on macOS
    let detailed_os = if ($os_name == "macOS") {
        let version = try { (^sw_vers -productVersion | str trim) } catch { "" }
        let name = try { (^sw_vers -productName | str trim) } catch { "" }
        if ($version != "" and $name != "") {
            $"($name) ($version)"
        } else {
            $os_name
        }
    } else {
        $os_name
    }
    
    print $"   OS: ($detailed_os)"
    print $"   Arch: ($arch)"  
    print $"   Kernel: ($kernel)"
    print $"   Shell: ($env.SHELL? | default 'unknown')"
    print ""
}

