#!/usr/bin/env nu

# Analyze Nushell Features Script
# Parses Cargo.toml to detect available features and their dependencies
#
# Usage:
#   analyze_nushell_features.nu                # Show all features
#   analyze_nushell_features.nu --validate     # Validate selected features
#   analyze_nushell_features.nu --export       # Export to JSON

use lib/common_lib.nu *

# Configuration for desired features
const DESIRED_FEATURES = [
    "mcp",
    "plugin",
    "sqlite",
    "trash-support",
    "system-clipboard"
]

# Main entry point
def main [
    --validate                # Validate desired features
    --export                  # Export feature analysis to JSON
    --show-all               # Show all features (not just desired)
] {
    log_info "Nushell Feature Analysis"

    # Check nushell source exists
    let nushell_dir = "./nushell"
    if not ($nushell_dir | path exists) {
        log_error "Nushell source not found at [$nushell_dir]"
        log_info "Run: download_nushell.nu <version>"
        exit 1
    }

    # Parse Cargo.toml
    let cargo_toml = $"($nushell_dir)/Cargo.toml"
    let features = parse_features $cargo_toml

    # Show version info
    let version = open $cargo_toml | get package.version
    log_info $"Analyzing Nushell version: ($version)"

    # Display features
    if $show_all {
        display_all_features $features
    } else {
        display_desired_features $features $DESIRED_FEATURES
    }

    # Validate if requested
    if $validate {
        validate_features $features $DESIRED_FEATURES
    }

    # Export if requested
    if $export {
        export_feature_analysis $features $version
    }
}

# Parse features from Cargo.toml
def parse_features [
    cargo_toml_path: string
]: nothing -> table {
    log_info "Parsing features from Cargo.toml..."

    let cargo_data = try {
        open $cargo_toml_path
    } catch {
        log_error $"Failed to read ($cargo_toml_path)"
        exit 1
    }

    # Extract features section
    let features_raw = try {
        $cargo_data | get features
    } catch {
        log_error "No [features] section found in Cargo.toml"
        exit 1
    }

    # Convert to table format
    let features_table = $features_raw
        | transpose feature dependencies
        | each {|row|
            {
                feature: $row.feature
                dependencies: ($row.dependencies | if ($in | describe) == "list" { $in } else { [] })
                is_default: ($row.feature == "default")
            }
        }

    log_success $"Found ($features_table | length) features"
    $features_table
}

# Display all available features
def display_all_features [
    features: table
] {
    log_info "\n=== All Available Features ==="

    $features | each {|feat|
        let dep_str = if ($feat.dependencies | is-empty) {
            "(no dependencies)"
        } else {
            $feat.dependencies | str join ", "
        }

        let marker = if $feat.is_default { " [DEFAULT]" } else { "" }
        print $"  • ($feat.feature)($marker)"
        print $"    Dependencies: ($dep_str)"
    }
}

# Display only desired features
def display_desired_features [
    features: table
    desired: list<string>
] {
    log_info "\n=== Desired Features Analysis ==="

    $desired | each {|desired_feat|
        let feat_info = $features | where feature == $desired_feat | first

        if ($feat_info | is-empty) {
            log_error $"Feature '($desired_feat)' NOT FOUND in Cargo.toml"
        } else {
            let dep_str = if ($feat_info.dependencies | is-empty) {
                "none"
            } else {
                $feat_info.dependencies | str join ", "
            }

            log_success $"✓ ($desired_feat)"
            log_info $"    Dependencies: ($dep_str)"
        }
    }
}

# Validate desired features exist and resolve dependencies
def validate_features [
    features: table
    desired: list<string>
] {
    log_info "\n=== Feature Validation ==="

    mut validation_passed = true

    # Check each desired feature exists
    for desired_feat in $desired {
        let feat_info = $features | where feature == $desired_feat

        if ($feat_info | is-empty) {
            log_error $"Feature '($desired_feat)' does not exist"
            $validation_passed = false
        } else {
            log_success $"✓ Feature '($desired_feat)' exists"

            # Validate dependencies recursively
            let feat_data = $feat_info | first
            if not ($feat_data.dependencies | is-empty) {
                validate_feature_dependencies $features $feat_data.dependencies 1
            }
        }
    }

    # Check for conflicts (optional - advanced)
    check_feature_conflicts $features $desired

    if $validation_passed {
        log_success "\n✅ All desired features are valid!"
    } else {
        log_error "\n❌ Feature validation failed"
        exit 1
    }
}

# Validate feature dependencies recursively
def validate_feature_dependencies [
    features: table
    dependencies: list<string>
    depth: int
] {
    let indent = (0..<$depth | each {|_| "    "} | str join)

    for dep in $dependencies {
        # Check if dependency is another feature
        let dep_info = $features | where feature == $dep

        if ($dep_info | is-empty) {
            # Not a feature, might be a crate dependency
            log_debug $"($indent)→ ($dep) (external crate)"
        } else {
            log_info $"($indent)→ ($dep) (feature)"

            # Recursively check dependencies
            let dep_data = $dep_info | first
            if not ($dep_data.dependencies | is-empty) {
                validate_feature_dependencies $features $dep_data.dependencies ($depth + 1)
            }
        }
    }
}

# Check for known feature conflicts
def check_feature_conflicts [
    features: table
    desired: list<string>
] {
    log_info "\nChecking for known feature conflicts..."

    # Known conflicts (example: native-tls vs rustls-tls)
    let conflict_groups = [
        ["native-tls", "rustls-tls"]
    ]

    mut has_conflicts = false

    for group in $conflict_groups {
        let found_in_group = $desired | where {|it| $it in $group}

        if ($found_in_group | length) > 1 {
            log_warn $"Potential conflict: ($found_in_group | str join ' vs ')"
            $has_conflicts = true
        }
    }

    if not $has_conflicts {
        log_success "No known conflicts detected"
    }
}

# Export feature analysis to JSON
def export_feature_analysis [
    features: table
    version: string
] {
    let output_file = "./tmp/feature_analysis.json"
    ensure_dir "./tmp"

    let analysis = {
        nushell_version: $version
        analyzed_at: (date now | format date "%Y-%m-%d %H:%M:%S")
        total_features: ($features | length)
        desired_features: $DESIRED_FEATURES
        all_features: $features
    }

    $analysis | to json | save -f $output_file
    log_success $"Feature analysis exported to: ($output_file)"
}

# Show feature dependency tree
def "main tree" [
    feature: string        # Feature to show tree for
] {
    let nushell_dir = "./nushell"
    let cargo_toml = $"($nushell_dir)/Cargo.toml"

    if not ($cargo_toml | path exists) {
        log_error "Nushell source not found"
        exit 1
    }

    let features = parse_features $cargo_toml
    let feat_info = $features | where feature == $feature

    if ($feat_info | is-empty) {
        log_error $"Feature '($feature)' not found"
        exit 1
    }

    log_info $"Dependency tree for: ($feature)"
    let feat_data = $feat_info | first
    show_dependency_tree $features $feature $feat_data.dependencies 0
}

# Recursively show dependency tree
def show_dependency_tree [
    features: table
    feature_name: string
    dependencies: list<string>
    depth: int
] {
    let indent = (0..<$depth | each {|_| "  "} | str join)
    print $"($indent)📦 ($feature_name)"

    if not ($dependencies | is-empty) {
        for dep in $dependencies {
            let dep_info = $features | where feature == $dep

            if ($dep_info | is-empty) {
                let dep_indent = (0..<($depth + 1) | each {|_| "  "} | str join)
                print $"($dep_indent)└─ ($dep) (external)"
            } else {
                let dep_data = $dep_info | first
                show_dependency_tree $features $dep $dep_data.dependencies ($depth + 1)
            }
        }
    }
}

# Generate build command with desired features
def "main build-cmd" [] {
    let nushell_dir = "./nushell"
    let cargo_toml = $"($nushell_dir)/Cargo.toml"

    if not ($cargo_toml | path exists) {
        log_error "Nushell source not found"
        exit 1
    }

    let features = parse_features $cargo_toml
    validate_features $features $DESIRED_FEATURES

    let features_str = $DESIRED_FEATURES | str join ","

    log_info "Build command with desired features:"
    print ""
    print $"  cargo build --workspace --release --features \"($features_str)\""
    print ""
    log_info "To build nushell with these features, run:"
    print $"  cd nushell && cargo build --workspace --release --features \"($features_str)\""
}

# List features by category
def "main categorize" [] {
    let nushell_dir = "./nushell"
    let cargo_toml = $"($nushell_dir)/Cargo.toml"

    if not ($cargo_toml | path exists) {
        log_error "Nushell source not found"
        exit 1
    }

    let features = parse_features $cargo_toml

    # Categorize features (heuristic based on name patterns)
    let categories = {
        "Core Features": ($features | where {|f| $f.feature in ["default", "full", "stable"]}),
        "Network Features": ($features | where {|f| $f.feature =~ "tls|network"}),
        "Plugin Features": ($features | where {|f| $f.feature =~ "plugin|mcp"}),
        "Storage Features": ($features | where {|f| $f.feature =~ "sqlite|trash"}),
        "System Features": ($features | where {|f| $f.feature =~ "clipboard|system"}),
        "Other Features": ($features | where {|f|
            $f.feature not-in ["default", "full", "stable"]
            and ($f.feature !~ "tls|network|plugin|mcp|sqlite|trash|clipboard|system")
        })
    }

    for category in ($categories | columns) {
        let feats = $categories | get $category

        if ($feats | length) > 0 {
            log_info $"\n=== ($category) ==="
            $feats | each {|f|
                print $"  • ($f.feature)"
            }
        }
    }
}
