#!/usr/bin/env nu

# Layered Module Resolver
# Provides unified resolution across 3 layers: System → Workspace → Infrastructure

# Selective imports (ADR-025 Phase 3 Layer 2).
# discover.nu files live at core/nulib/{taskservs,providers,clusters}/ — outside
# lib_provisioning/. Absolute paths from nulib/ root used.
use taskservs/discover.nu [discover-taskservs get-taskserv-info]
use providers/discover.nu [discover-providers get-provider-info]
use clusters/discover.nu [discover-clusters get-cluster-info]

# Resolve module path with layer information
# Returns: {path: string, layer: string, name: string, type: string, found: bool}
export def resolve-module [
    module_name: string
    module_type: string  # "taskserv", "provider", "cluster"
    --workspace: string = ""  # Workspace path for Layer 2
    --infra: string = ""      # Infrastructure path for Layer 3
] {
    # Layer 3: Infrastructure-specific (highest priority)
    if ($infra | is-not-empty) and ($infra | path exists) {
        let infra_path = match $module_type {
            "taskserv" => ($infra | path join ".taskservs" $module_name)
            "provider" => ($infra | path join ".providers" $module_name)
            "cluster" => ($infra | path join ".clusters" $module_name)
            _ => ""
        }

        if ($infra_path | path exists) {
            return {
                path: $infra_path
                layer: "infra"
                layer_number: 3
                name: $module_name
                type: $module_type
                found: true
            }
        }
    }

    # Layer 2: Workspace-shared (medium priority)
    if ($workspace | is-not-empty) and ($workspace | path exists) {
        let workspace_path = match $module_type {
            "taskserv" => ($workspace | path join ".taskservs" $module_name)
            "provider" => ($workspace | path join ".providers" $module_name)
            "cluster" => ($workspace | path join ".clusters" $module_name)
            _ => ""
        }

        if ($workspace_path | path exists) {
            return {
                path: $workspace_path
                layer: "workspace"
                layer_number: 2
                name: $module_name
                type: $module_type
                found: true
            }
        }
    }

    # Layer 1: System extensions (lowest priority)
    let system_result = resolve-system-module $module_name $module_type

    if $system_result.found {
        return $system_result
    }

    # Not found in any layer
    {
        path: ""
        layer: "none"
        layer_number: 0
        name: $module_name
        type: $module_type
        found: false
    }
}

# Resolve module from system extensions (Layer 1)
def resolve-system-module [name: string, type: string] {
    match $type {
        "taskserv" => {
            let result = (do {
                let info = (get-taskserv-info $name)
                {
                    path: $info.schema_path
                    layer: "system"
                    layer_number: 1
                    name: $name
                    type: "taskserv"
                    found: true
                    metadata: $info
                }
            } | complete)

            if $result.exit_code == 0 {
                $result.stdout
            } else {
                {found: false}
            }
        }
        "provider" => {
            let result = (do {
                let info = (get-provider-info $name)
                {
                    path: $info.schema_path
                    layer: "system"
                    layer_number: 1
                    name: $name
                    type: "provider"
                    found: true
                    metadata: $info
                }
            } | complete)

            if $result.exit_code == 0 {
                $result.stdout
            } else {
                {found: false}
            }
        }
        "cluster" => {
            let result = (do {
                let info = (get-cluster-info $name)
                {
                    path: $info.schema_path
                    layer: "system"
                    layer_number: 1
                    name: $name
                    type: "cluster"
                    found: true
                    metadata: $info
                }
            } | complete)

            if $result.exit_code == 0 {
                $result.stdout
            } else {
                {found: false}
            }
        }
        _ => {
            {found: false}
        }
    }
}

# List all available modules across layers
export def list-modules-by-layer [
    module_type: string
    --workspace: string = ""
    --infra: string = ""
] {
    mut modules = []

    # Layer 1: System
    let system_modules = match $module_type {
        "taskserv" => (discover-taskservs | each {|m| $m | insert layer "system" | insert layer_number 1})
        "provider" => (discover-providers | each {|m| $m | insert layer "system" | insert layer_number 1})
        "cluster" => (discover-clusters | each {|m| $m | insert layer "system" | insert layer_number 1})
        _ => []
    }
    $modules = ($modules | append $system_modules)

    # Layer 2: Workspace
    if ($workspace | is-not-empty) and ($workspace | path exists) {
        let ws_dir = match $module_type {
            "taskserv" => ($workspace | path join ".taskservs")
            "provider" => ($workspace | path join ".providers")
            "cluster" => ($workspace | path join ".clusters")
            _ => ""
        }

        if ($ws_dir | path exists) {
            let ws_modules = (ls $ws_dir | where type == "dir" | each {|dir|
                {
                    name: ($dir.name | path basename)
                    type: $module_type
                    layer: "workspace"
                    layer_number: 2
                    path: $dir.name
                }
            })
            $modules = ($modules | append $ws_modules)
        }
    }

    # Layer 3: Infrastructure
    if ($infra | is-not-empty) and ($infra | path exists) {
        let infra_dir = match $module_type {
            "taskserv" => ($infra | path join ".taskservs")
            "provider" => ($infra | path join ".providers")
            "cluster" => ($infra | path join ".clusters")
            _ => ""
        }

        if ($infra_dir | path exists) {
            let infra_modules = (ls $infra_dir | where type == "dir" | each {|dir|
                {
                    name: ($dir.name | path basename)
                    type: $module_type
                    layer: "infra"
                    layer_number: 3
                    path: $dir.name
                }
            })
            $modules = ($modules | append $infra_modules)
        }
    }

    $modules
}

# Show effective modules (deduplicated by resolution order)
export def show-effective-modules [
    module_type: string
    --workspace: string = ""
    --infra: string = ""
] {
    let all_modules = (list-modules-by-layer $module_type --workspace $workspace --infra $infra)

    # Group by name and pick highest layer number
    $all_modules
    | group-by name
    | items {|name, versions|
        let effective = ($versions | sort-by layer_number | reverse | first)
        $effective | insert overrides (($versions | length) - 1)
    }
}

# Determine target layer from context
export def determine-layer [
    --workspace: string = ""
    --infra: string = ""
    --level: string = ""  # Explicit level: "workspace", "infra", or auto-detect
] {
    # Explicit level takes precedence
    if ($level | is-not-empty) {
        if $level == "workspace" {
            return {
                layer: "workspace"
                layer_number: 2
                path: $workspace
            }
        } else if $level == "infra" {
            return {
                layer: "infra"
                layer_number: 3
                path: $infra
            }
        }
    }

    # Auto-detect based on current directory
    let pwd = $env.PWD

    # Check if we're in an infrastructure directory
    if ($pwd | str contains "/infra/") {
        let infra_path = if ($infra | is-not-empty) {
            $infra
        } else {
            # Try to find infra path from current directory
            let parts = ($pwd | path split)
            let infra_idx = ($parts | enumerate | where item == "infra" | get index | first)
            if ($infra_idx | is-not-empty) {
                let infra_parts = ($parts | take ($infra_idx + 2))
                $infra_parts | path join
            } else {
                $pwd
            }
        }

        return {
            layer: "infra"
            layer_number: 3
            path: $infra_path
        }
    }

    # Check if we're in a workspace directory
    if ($workspace | is-not-empty) and ($workspace | path exists) {
        return {
            layer: "workspace"
            layer_number: 2
            path: $workspace
        }
    }

    # Check if current directory has .taskservs (workspace marker)
    if (($pwd | path join ".taskservs") | path exists) and (($pwd | path join "infra") | path exists) {
        return {
            layer: "workspace"
            layer_number: 2
            path: $pwd
        }
    }

    # Default to infrastructure level
    {
        layer: "infra"
        layer_number: 3
        path: ($infra | default $pwd)
    }
}

# Print resolution information for debugging
export def print-resolution [resolution: record] {
    if $resolution.found {
        print $"✅ Found ($resolution.name) at Layer ($resolution.layer_number) \(($resolution.layer)\)"
        print $"   Path: ($resolution.path)"
    } else {
        print $"❌ Module ($resolution.name) not found in any layer"
    }
}
