#!/usr/bin/env nu
# Automated try-catch to Result pattern refactorer
# Refactors 276+ try-catch blocks to use Result pattern helpers
# Version: 1.0

use std log

# Configuration
let config = {
    dry_run: false
    backup: true
    verbose: true
    patterns: [
        "bash_check"      # try { bash -c ... | complete } catch { ... }
        "bash_or"         # try { bash ... } catch { fallback }
        "json_read"       # try { open file | from json } catch { ... }
        "bash_wrap"       # try { bash -c ... } catch { ... }
    ]
}

# Report structure
mut report = {
    total_files: 0
    files_processed: 0
    patterns_found: {}
    errors: []
    changes_by_file: {}
}

# Add result.nu import if not present
def ensure-result-import [file_path: string] {
    let content_result = (do { open $file_path } | complete)
    if $content_result.exit_code != 0 {
        return false
    }
    let content = $content_result.stdout

    # Check if already imported
    if ($content | str contains "use.*result.nu") {
        return false
    }

    # Check where to insert import
    let lines = ($content | lines)
    let insert_pos = (
        $lines
        | enumerate
        | find -a {|x| $x.item =~ "^(use|def|export)" }
        | get 0?.index
        | default 0
    )

    # Insert import
    let new_lines = (
        $lines
        | enumerate
        | each {|x|
            if $x.index == $insert_pos {
                ["use lib_provisioning/result.nu *", $x.item]
            } else {
                $x.item
            }
        }
        | flatten
    )

    true
}

# Pattern 1: bash-check (try { bash -c ... | complete } catch { {exit_code: 1, stderr: $err} })
def refactor-bash-check [content: string] -> {changed: bool, content: string} {
    # Match pattern: try { bash -c $"..." | complete } catch {|err| {exit_code: 1, stderr: $err} }
    let pattern = 'try\s*\{\s*bash\s+-c\s+\$"([^"]+)"\s*\|\s*complete\s*\}\s*catch\s*\{\|err\|\s*\{exit_code:\s*1,\s*stderr:\s*\$err\s*\}\s*\}'

    if not ($content =~ $pattern) {
        return {changed: false, content: $content}
    }

    # Replace with bash-check helper
    let new_content = (
        $content
        | str replace -a -m $pattern 'bash-check $"$1"'
    )

    {changed: true, content: $new_content}
}

# Pattern 2: bash-or (try { bash -c ... } catch { fallback })
def refactor-bash-or [content: string] -> {changed: bool, content: string} {
    # Match pattern: try { bash -c $"..." } catch { fallback_value }
    let pattern = 'try\s*\{\s*bash\s+-c\s+\$"([^"]+)"\s*\}\s*catch\s*\{\s*([^}]+)\s*\}'

    if not ($content =~ $pattern) {
        return {changed: false, content: $content}
    }

    # Replace with bash-or helper
    let new_content = (
        $content
        | str replace -a -m $pattern 'bash-or $"$1" $2'
    )

    {changed: true, content: $new_content}
}

# Pattern 3: json-read (try { open file | from json } catch { ... })
def refactor-json-read [content: string] -> {changed: bool, content: string} {
    # Match pattern: try { open $path | from json } catch { default_value }
    let pattern = 'try\s*\{\s*open\s+(\$\w+)\s*\|\s*from\s+json\s*\}\s*catch\s*\{\s*([^}]+)\s*\}'

    if not ($content =~ $pattern) {
        return {changed: false, content: $content}
    }

    # Replace with json-read helper + match-result
    let new_content = (
        $content
        | str replace -a -m $pattern '(json-read $1) | match-result {|data| $data} {|_err| $2}'
    )

    {changed: true, content: $new_content}
}

# Pattern 4: bash-wrap (try { bash -c ... } catch { error_record })
def refactor-bash-wrap [content: string] -> {changed: bool, content: string} {
    # Match pattern: try { bash -c $"..." } catch {|err| error_record }
    let pattern = 'try\s*\{\s*bash\s+-c\s+\$"([^"]+)"\s*\}\s*catch\s*\{\|err\|\s*([^}]+)\s*\}'

    if not ($content =~ $pattern) {
        return {changed: false, content: $content}
    }

    # Replace with bash-wrap helper
    let new_content = (
        $content
        | str replace -a -m $pattern '(bash-wrap $"$1") | match-result {|output| output} {|err| $2}'
    )

    {changed: true, content: $new_content}
}

# Apply all refactoring patterns
def apply-patterns [content: string] -> {changed: bool, content: string, patterns_applied: list} {
    mut result = {changed: false, content: $content, patterns_applied: []}

    # Apply each pattern
    for pattern in ["bash_check", "bash_or", "json_read", "bash_wrap"] {
        let pattern_result = (
            match $pattern {
                "bash_check" => (refactor-bash-check $result.content)
                "bash_or" => (refactor-bash-or $result.content)
                "json_read" => (refactor-json-read $result.content)
                "bash_wrap" => (refactor-bash-wrap $result.content)
                _ => {changed: false, content: $result.content}
            }
        )

        if $pattern_result.changed {
            $result.changed = true
            $result.content = $pattern_result.content
            $result.patterns_applied = ($result.patterns_applied | append $pattern)
        }
    }

    $result
}

# Refactor single file
def refactor-file [file_path: string] -> record {
    let content_result = (do { open $file_path } | complete)
    if $content_result.exit_code != 0 {
        return {
            file: $file_path
            changed: false
            patterns_applied: []
            import_added: false
            backup_created: false
        }
    }
    let original_content = $content_result.stdout

    # Ensure result.nu import
    let import_added = (ensure-result-import $file_path)

    # Apply refactoring patterns
    let refactor_result = (apply-patterns $original_content)

    # Check if any changes
    let has_changes = ($refactor_result.changed or $import_added)

    if $has_changes and (not $config.dry_run) {
        # Create backup
        if $config.backup {
            let backup_result = (do { bash -c $"cp ($file_path) ($file_path).bak" } | complete)
            if $backup_result.exit_code != 0 {
                # Log but continue
                if $config.verbose {
                    print $"Warning: backup failed for ($file_path)"
                }
            }
        }

        # Write new content
        let save_result = (do { $refactor_result.content | save -f $file_path } | complete)
        if $save_result.exit_code != 0 {
            if $config.verbose {
                print $"Warning: save failed for ($file_path)"
            }
        }
    }

    {
        file: $file_path
        changed: $has_changes
        patterns_applied: $refactor_result.patterns_applied
        import_added: $import_added
        backup_created: ($has_changes and $config.backup)
    }
}

# Main refactoring loop
def main [] {
    print "🔧 Automated try-catch → Result Pattern Refactorer"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print $"Dry run: ($config.dry_run)"
    print $"Backup enabled: ($config.backup)"
    print ""

    # Find all .nu files with try-catch
    print "📁 Scanning for try-catch patterns..."
    let files = (
        glob "provisioning/core/nulib/**/*.nu"
        | par-each {|f|
            if (open $f | str contains "try\s*{") {
                $f
            } else {
                null
            }
        }
        | filter {|x| $x != null}
    )

    $report.total_files = ($files | length)
    print $"Found ($($files | length)) files with try-catch patterns"
    print ""

    # Process files
    print "🔄 Processing files..."
    let results = (
        $files | par-each {|file|
            refactor-file $file
        }
    )

    # Generate report
    mut changed_count = 0
    mut pattern_counts = {}

    for result in $results {
        if $result.changed {
            $changed_count += 1
            $report.changes_by_file = ($report.changes_by_file | insert $result.file {
                patterns: $result.patterns_applied
                backup: $result.backup_created
            })

            for pattern in $result.patterns_applied {
                let current = ($pattern_counts | get -i $pattern | default 0)
                $pattern_counts = ($pattern_counts | insert $pattern ($current + 1))
            }
        }

        if $config.verbose {
            let status = (if $result.changed { "✅ CHANGED" } else { "⏭️  SKIPPED" })
            print $"($status): ($result.file | path basename)"
        }
    }

    $report.files_processed = $changed_count
    $report.patterns_found = $pattern_counts

    # Final report
    print ""
    print "📊 REFACTORING REPORT"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print $"Total files scanned: ($report.total_files)"
    print $"Files changed: ($report.files_processed)"
    print ""
    print "Patterns refactored:"
    for {pattern, count} in ($report.patterns_found | to entries) {
        print $"  • ($pattern): ($count) occurrences"
    }

    if $config.dry_run {
        print ""
        print "⚠️  DRY RUN MODE - No files were modified"
        print "Run with --no-dry-run to apply changes"
    } else if $config.backup {
        print ""
        print "✅ Backups created for all changed files (.bak)"
    }

    print ""
    print "Next steps:"
    print "1. Review changes: git diff"
    print "2. Verify helpers are imported: grep 'use lib_provisioning/result.nu' *.nu"
    print "3. Test: cargo test (if applicable)"
    print "4. Commit: git add -A && git commit -m 'refactor: eliminate try-catch blocks'"
}

# Parse command line arguments
let args = $env.ARGS.positional
if ($args | any {|arg| $arg == "--apply"}) {
    $config.dry_run = false
}
if ($args | any {|arg| $arg == "--verbose"}) {
    $config.verbose = true
}

# Run main
main
