#!/usr/bin/env nu
# Load extension metadata and build Directed Acyclic Graph (DAG)
# Performs topological sort for initialization order
#
# Usage:
#   nu load-extensions.nu --extensions-dir <path> --output-file <path>
#   nu load-extensions.nu # Uses defaults

def main [
    --extensions-dir: path = "extensions"                          # Path to extensions directory
    --output-file: path = "config/extensions-dag.json"            # Output DAG JSON file
    --verbose                                                      # Enable verbose output
] {
    print "🔍 Loading extension metadata..."
    if $verbose { print $"   Extensions dir: ($extensions_dir)" }

    # Find all metadata.ncl files using glob (exclude polkadot deployment configs)
    let metadata_files = (
        glob ($extensions_dir + "/**/metadata.ncl")
        | where { |f| not ($f | str contains "polkadot") }
        | sort
    )

    if ($metadata_files | is-empty) {
        print "⚠️  No extension metadata files found"
        return 1
    }

    print $"📂 Found ($metadata_files | length) extensions"

    # Load all metadata files
    let extensions = (
        $metadata_files
        | each { |file|
            if $verbose { print $"   Loading: ($file)" }
            let result = (do {
                nickel export $file | from json
            } | complete)
            if $result.exit_code == 0 {
                $result.stdout
            } else {
                print $"❌ Failed to load: ($file)"
                error make { msg: $"Failed to export ($file)" }
            }
        }
    )

    print $"✅ Loaded ($extensions | length) extensions"

    if $verbose {
        print "\nExtension Summary:"
        $extensions | each { |ext|
            let deps_str = ($ext.dependencies | str join ', ')
            if ($ext.dependencies | is-empty) {
                print $"  • ($ext.name) v($ext.version) [($ext.category)] - deps: []"
            } else {
                print $"  • ($ext.name) v($ext.version) [($ext.category)] - deps: [($deps_str)]"
            }
        }
    }

    # Build DAG and detect cycles
    let dag_result = (build_dag $extensions)

    if ("error" in $dag_result) {
        print $"❌ DAG Error: ($dag_result.error)"
        return 1
    }

    let dag = $dag_result

    # Topological sort
    let sorted_result = (topological_sort $extensions $dag)

    if ("error" in $sorted_result) {
        print $"❌ Topological Sort Error: ($sorted_result.error)"
        return 1
    }

    let init_order = $sorted_result

    if $verbose {
        print "\nInitialization Order (Topological Sort):"
        $init_order | enumerate | each { |item|
            print $"  ($item.index). ($item.item)"
        }
    }

    # Build output structure
    let output = {
        extensions: $extensions,
        dag: $dag,
        initialization_order: $init_order,
        metadata: {
            total_extensions: ($extensions | length),
            exported_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
            schema_version: "1.0",
            statistics: (build_stats $extensions),
        },
    }

    # Write output
    let dir = $output_file | path dirname
    if not ($dir | path exists) {
        mkdir $dir
    }

    $output | to json --indent 2 | save --force $output_file

    print $"✅ Extension DAG exported to: ($output_file)"
    print $"   Extensions: ($output.metadata.total_extensions)"
    print $"   Status: Ready for ai-service initialization"

    0
}

# Build DAG from extension dependencies
def build_dag [extensions: list] {
    let ext_names = ($extensions | each { |e| $e.name })

    # Validate all dependencies exist
    let invalid_deps = (
        $extensions
        | each { |ext|
            $ext.dependencies
            | each { |dep|
                if not ($ext_names | any { |n| $n == $dep }) {
                    {extension: $ext.name, missing_dep: $dep}
                } else {
                    null
                }
            }
            | compact
        }
        | flatten
    )

    if not ($invalid_deps | is-empty) {
        let missing = ($invalid_deps | each { |d| $"($d.extension)->($d.missing_dep)" } | str join ", ")
        return {error: $"Invalid dependencies: ($missing)"}
    }

    # Build edges (node -> dependencies)
    let edges = (
        $extensions
        | each { |ext|
            $ext.dependencies
            | each { |dep|
                {from: $ext.name, to: $dep, label: "depends_on"}
            }
        }
        | flatten
    )

    {
        nodes: $ext_names,
        edges: $edges,
    }
}

# Topological sort using DFS
def topological_sort [extensions: list, dag: record] {
    let ext_names = $dag.nodes
    let edges = $dag.edges

    # Build adjacency list (reverse: what depends on each node)
    let adj_list = (
        $ext_names
        | each { |node|
            let deps = (
                $edges
                | where { |e| $e.from == $node }
                | each { |e| $e.to }
            )
            {node: $node, deps: $deps}
        }
    )

    # Simple sort by counting in-degree and processing in order
    # Extensions with no dependencies come first
    let no_deps = ($adj_list | where { |n| ($n.deps | is-empty) } | each { |n| $n.node } | sort)
    let with_deps = ($adj_list | where { |n| ($n.deps | length) > 0 } | each { |n| $n.node } | sort)

    # Check for cycles (simple check: if an extension depends on something not in the list)
    let all_ext_names = ($extensions | each { |e| $e.name })
    let all_deps = (
        $extensions
        | each { |e| $e.dependencies }
        | flatten
    )

    let invalid_deps = ($all_deps | where { |d| not ($all_ext_names | any { |n| $n == $d }) })

    if not ($invalid_deps | is-empty) {
        return {error: $"Invalid dependencies found: ($invalid_deps | str join ', ')"}
    }

    # Simple ordering: return no_deps first, then with_deps sorted by number of dependencies
    let sorted = (
        [$no_deps, (
            $with_deps
            | each { |name|
                let dep_count = ($extensions | where { |e| $e.name == $name } | first | get dependencies | length)
                {name: $name, dep_count: $dep_count}
            }
            | sort-by dep_count
            | each { |n| $n.name }
        )]
        | flatten
    )

    $sorted
}

# Build statistics
def build_stats [extensions: list] {
    let categories = ($extensions | each { |e| $e.category } | sort | uniq)
    let by_category = (
        $categories
        | each { |cat|
            let count = ($extensions | where { |e| $e.category == $cat } | length)
            {category: $cat, count: $count}
        }
    )

    let total_deps = (
        $extensions
        | each { |e| $e.dependencies | length }
        | math sum
    )

    {
        by_category: $by_category,
        total_dependencies: $total_deps,
        extension_count: ($extensions | length),
    }
}

# Utility: List extensions by category
export def list_by_category [
    --extensions-dir: path = "extensions"
] {
    let metadata_files = (glob ($extensions_dir + "/**/metadata.ncl"))

    let extensions = (
        $metadata_files
        | each { |file|
            let result = (do {
                nickel export $file | from json
            } | complete)
            if $result.exit_code == 0 {
                $result.stdout
            } else {
                null
            }
        }
        | compact
    )

    let categories = ($extensions | each { |e| $e.category } | sort | uniq)

    $categories | each { |cat|
        let exts = ($extensions | where { |e| $e.category == $cat })
        print $"($cat):"
        $exts | each { |ext|
            print $"  • ($ext.name) v($ext.version)"
        }
        print ""
    }
}

# Utility: Check extension dependencies
export def check_dependencies [
    --extensions-dir: path = "extensions"
] {
    let metadata_files = (glob ($extensions_dir + "/**/metadata.ncl") | sort)

    let extensions = (
        $metadata_files
        | each { |file|
            nickel export $file | from json
        }
    )

    print "🔍 Extension Dependency Check"
    print "=============================="
    print ""

    let ext_names = ($extensions | each { |e| $e.name })

    $extensions | each { |ext|
        if ($ext.dependencies | is-empty) {
            print $"✅ ($ext.name): No dependencies"
        } else {
            print $"($ext.name):"
            $ext.dependencies | each { |dep|
                if ($ext_names | any { |n| $n == $dep }) {
                    print $"  ✅ → ($dep)"
                } else {
                    print $"  ❌ → ($dep) [NOT FOUND]"
                }
            }
        }
        print ""
    }
}

main
