# Extensions Management Commands

use ../lib_provisioning/extensions *
use ../lib_provisioning/config/accessor.nu *
use ../lib_provisioning/utils/nickel_processor.nu [ncl-eval-soft, default-ncl-paths]

# Resolve the taskservs directory: PROVISIONING_TASKSERVS_PATH → config → $PROVISIONING/extensions/taskservs.
def resolve-taskservs-dir [] : nothing -> string {
    let from_env = ($env.PROVISIONING_TASKSERVS_PATH? | default "")
    if ($from_env | is-not-empty) { return $from_env }
    let from_config = (get-taskservs-path)
    if ($from_config | is-not-empty) { return $from_config }
    ($env.PROVISIONING? | default "/usr/local/provisioning") | path join "extensions" "taskservs"
}

# Load metadata.ncl for each taskserv via nickel export and aggregate provides/requires/conflicts_with.
def load-taskserv-capabilities [] : nothing -> list<record> {
    let ts_dir = (resolve-taskservs-dir)
    if not ($ts_dir | path exists) { return [] }

    glob ($ts_dir | path join "*")
    | where ($it | path type) == "dir"
    | each { |ts_path|
        let meta_path = ($ts_path | path join "metadata.ncl")
        if not ($meta_path | path exists) {
            null
        } else {
            let prov = ($env.PROVISIONING? | default "/usr/local/provisioning")
            let m = (ncl-eval-soft $meta_path (default-ncl-paths "") null)
            if ($m | is-not-empty) {
                {
                    name:          $m.name,
                    version:       $m.version,
                    description:   $m.description,
                    provides:      ($m.provides? | default []),
                    requires:      ($m.requires? | default []),
                    conflicts_with: ($m.conflicts_with? | default []),
                }
            } else { null }
        }
    }
    | where ($it != null)
}

# List available extensions
export def "main extensions list" [
    --type: string = ""  # Filter by type: provider, taskserv, or all
    --helpinfo (-h)      # Show help
] {
    if $helpinfo {
        print "List available extensions"
        return
    }

    match $type {
        "provider" => {
            print "Available Provider Extensions:"
            list-providers
        }
        "taskserv" => {
            print "Available TaskServ Extensions:"
            list-taskservs
        }
        _ => {
            print "Available Extensions:"
            print "\nProviders:"
            list-providers

            print "\nTaskServs:"
            list-taskservs
        }
    }
}

# Show extension details
export def "main extensions show" [
    name: string         # Extension name
    --helpinfo (-h)      # Show help
] {
    if $helpinfo {
        print "Show details for a specific extension"
        return
    }

    let provider = (get-provider $name)
    let taskserv = (get-taskserv $name)

    if ($provider | is-not-empty) {
        print $"Provider Extension: ($name)"
        $provider
    } else if ($taskserv | is-not-empty) {
        print $"TaskServ Extension: ($name)"
        $taskserv
    } else {
        print $"Extension '($name)' not found"
    }
}

# Initialize extensions
export def "main extensions init" [
    --helpinfo (-h)      # Show help
] {
    if $helpinfo {
        print "Initialize extension registry"
        return
    }

    init-registry
    print "Extension registry initialized"
}

# Show current profile
export def "main profile show" [
    --helpinfo (-h)      # Show help
] {
    if $helpinfo {
        print "Show current access profile"
        return
    }

    show-profile | table
}

# Create example profiles
export def "main profile create-examples" [
    --helpinfo (-h)      # Show help
] {
    if $helpinfo {
        print "Create example profile files"
        return
    }

    create-example-profiles
}

# List capability declarations across all taskservs (provides + requires).
export def "main extensions capabilities" [
    --type (-t): string = "all"  # Filter: "provides", "requires", or "all"
    --helpinfo (-h)              # Show help
] : nothing -> any {
    if $helpinfo {
        print "List capability declarations across all taskservs"
        print "  --type: provides | requires | all (default: all)"
        return
    }

    let caps = (load-taskserv-capabilities)
    if ($caps | is-empty) {
        print "No taskservs found or metadata.ncl missing."
        return
    }

    match $type {
        "provides" => {
            $caps | each { |ts|
                $ts.provides | each { |p| { taskserv: $ts.name, provides_id: $p.id, version: $p.version, interface: $p.interface } }
            } | flatten | table
        }
        "requires" => {
            $caps | each { |ts|
                $ts.requires | each { |r| { taskserv: $ts.name, capability: $r.capability, kind: $r.kind } }
            } | flatten | table
        }
        _ => {
            $caps | each { |ts|
                {
                    taskserv:      $ts.name,
                    provides:      ($ts.provides | each { |p| $p.id } | str join ", "),
                    requires:      ($ts.requires | each { |r| $"($r.capability)[($r.kind)]" } | str join ", "),
                    conflicts_with: ($ts.conflicts_with | str join ", "),
                }
            } | table
        }
    }
}

# Show inter-extension dependency graph derived from provides/requires metadata.
export def "main extensions graph" [
    --format (-f): string = "table"  # Output format: table, dot
    --helpinfo (-h)                  # Show help
] : nothing -> any {
    if $helpinfo {
        print "Show inter-extension dependency graph from provides/requires metadata"
        print "  --format: table | dot (default: table)"
        return
    }

    let caps = (load-taskserv-capabilities)
    if ($caps | is-empty) {
        print "No taskservs found."
        return
    }

    # Build provides index: capability_id -> taskserv name
    let provides_index = ($caps | each { |ts|
        $ts.provides | each { |p| { cap: $p.id, provider: $ts.name } }
    } | flatten)

    # Build edges: (requirer, capability, provider, kind)
    let edges = ($caps | each { |ts|
        $ts.requires | each { |r|
            let provider = ($provides_index | where cap == $r.capability | get provider?.0 | default "unresolved")
            { from: $ts.name, capability: $r.capability, to: $provider, kind: $r.kind }
        }
    } | flatten)

    match $format {
        "table" => {
            $edges | table
        }
        "dot" => {
            print "digraph extensions {"
            print "  rankdir=LR;"
            for edge in $edges {
                let style = if $edge.kind == "Required" { "" } else { " style=dashed" }
                print $"  \"($edge.from)\" -> \"($edge.to)\" [label=\"($edge.capability)\"($style)];"
            }
            print "}"
        }
        _ => {
            error make { msg: $"Unknown format '($format)'. Valid: table, dot" }
        }
    }
}
