# Extension Registry
# Manages registration and lookup of providers, taskservs, and hooks

# Selective imports (ADR-025 Phase 3 Layer 2).
# config/accessor star-import was dead — dropped.
use lib_provisioning/extensions/loader.nu [discover-providers discover-taskservs]

# Get default extension registry
export def get-default-registry [] {
    {
        providers: {},
        taskservs: {},
        hooks: {
            pre_server_create: [],
            post_server_create: [],
            pre_server_delete: [],
            post_server_delete: [],
            pre_taskserv_install: [],
            post_taskserv_install: [],
            pre_taskserv_delete: [],
            post_taskserv_delete: []
        }
    }
}

# Get registry cache file path
def get-registry-cache-file [] {
    let cache_dir = ($env.HOME | path join ".cache" "provisioning")
    if not ($cache_dir | path exists) {
        mkdir $cache_dir
    }
    $cache_dir | path join "extension-registry.json"
}

# Load registry from cache or initialize
export def load-registry [] {
    let cache_file = (get-registry-cache-file)
    if ($cache_file | path exists) {
        open $cache_file
    } else {
        get-default-registry
    }
}

# Save registry to cache
export def save-registry [registry: record] {
    let cache_file = (get-registry-cache-file)
    $registry | to json | save -f $cache_file
}

# Initialize extension registry
export def init-registry [] {
    # Load all discovered extensions
    let providers = (discover-providers)
    let taskservs = (discover-taskservs)

    # Build provider entries
    let provider_entries = ($providers | reduce -f {} {|provider, acc|
        let provider_entry = {
            name: $provider.name
            path: $provider.path
            manifest: $provider.manifest
            entry_point: ($provider.path | path join "nulib" $provider.name)
            available: ($provider.path | path join "nulib" $provider.name | path exists)
        }

        if $provider_entry.available {
            $acc | insert $provider.name $provider_entry
        } else {
            $acc
        }
    })

    # Build taskserv entries
    let taskserv_entries = ($taskservs | reduce -f {} {|taskserv, acc|
        let taskserv_entry = {
            name: $taskserv.name
            path: $taskserv.path
            manifest: $taskserv.manifest
            profiles: (glob ($taskserv.path | path join "*") | where ($it | path type) == "dir" | each { path basename })
            available: true
        }

        $acc | insert $taskserv.name $taskserv_entry
    })

    # Build hooks (simplified for now)
    let hook_entries = (get-default-registry).hooks

    # Build final registry
    let registry = {
        providers: $provider_entries
        taskservs: $taskserv_entries
        hooks: $hook_entries
    }

    # Save registry to cache
    save-registry $registry
}

# Register a provider
export def --env register-provider [name: string, path: string, manifest: record] {
    let provider_entry = {
        name: $name
        path: $path
        manifest: $manifest
        entry_point: ($path | path join "nulib" $name)
        available: ($path | path join "nulib" $name | path exists)
    }

    if $provider_entry.available {
        let current_registry = ($env.EXTENSION_REGISTRY? | default (get-default-registry))
        $env.EXTENSION_REGISTRY = ($current_registry
            | update providers ($current_registry.providers | insert $name $provider_entry))
    }
}

# Register a taskserv
export def --env register-taskserv [name: string, path: string, manifest: record] {
    let taskserv_entry = {
        name: $name
        path: $path
        manifest: $manifest
        profiles: (glob ($path | path join "*") | where ($it | path type) == "dir" | each { path basename })
        available: true
    }

    let current_registry = ($env.EXTENSION_REGISTRY? | default (get-default-registry))
    $env.EXTENSION_REGISTRY = ($current_registry
        | update taskservs ($current_registry.taskservs | insert $name $taskserv_entry))
}

# Register a hook
export def --env register-hook [hook_type: string, hook_path: string, extension_name: string] {
    let hook_entry = {
        path: $hook_path
        extension: $extension_name
        enabled: true
    }

    let current_registry = ($env.EXTENSION_REGISTRY? | default (get-default-registry))
    let hooks = ($current_registry.hooks? | default {})
    let current_hooks = if ($hook_type in ($hooks | columns)) { $hooks | get $hook_type } else { [] }
    $env.EXTENSION_REGISTRY = ($current_registry
        | update hooks ($current_registry.hooks? | default (get-default-registry).hooks
            | update $hook_type ($current_hooks | append $hook_entry)))
}

# Get registered provider
export def get-provider [name: string] {
    let registry = (load-registry)
    if ($name in ($registry.providers | columns)) { $registry.providers | get $name } else { {} }
}

# List all registered providers
export def list-providers [] {
    let registry = (load-registry)
    $registry.providers | items {|name, provider|
        {
            name: $name
            path: $provider.path
            version: $provider.manifest.version
            available: $provider.available
            source: ($provider.path | str replace $env.HOME "~")
        }
    } | flatten
}

# Get registered taskserv
export def get-taskserv [name: string] {
    let registry = (load-registry)
    if ($name in ($registry.taskservs | columns)) { $registry.taskservs | get $name } else { {} }
}

# List all registered taskservs
export def list-taskservs [] {
    let registry = (load-registry)
    $registry.taskservs | items {|name, taskserv|
        {
            name: $name
            path: $taskserv.path
            version: $taskserv.manifest.version
            profiles: ($taskserv.profiles | str join ", ")
            source: ($taskserv.path | str replace $env.HOME "~")
        }
    } | flatten
}

# Execute hooks
export def execute-hooks [hook_type: string, context: record] {
    let registry = (load-registry)
    let hooks_all = ($registry.hooks? | default {})
    let hooks = if ($hook_type in ($hooks_all | columns)) { $hooks_all | get $hook_type } else { [] }
    $hooks | where enabled | each {|hook|
        let result = (do { nu $hook.path ($context | to json) } | complete)
        if $result.exit_code == 0 {
            {
                hook: $hook.path
                extension: $hook.extension
                output: $result.stdout
                success: true
            }
        } else {
            {
                hook: $hook.path
                extension: $hook.extension
                error: $result.stderr
                success: false
            }
        }
    }
}

# Check if provider exists (core or extension)
export def provider-exists [name: string] {
    let core_providers = ["aws", "local", "upcloud"]
    ($name in $core_providers) or ((get-provider $name) | is-not-empty)
}

# Check if taskserv exists (core or extension)
export def taskserv-exists [name: string] {
    let core_path = ((get-taskservs-path) | path join $name)
    let extension_taskserv = (get-taskserv $name)

    ($core_path | path exists) or ($extension_taskserv | is-not-empty)
}

# Get taskserv path (core or extension)
export def get-taskserv-path [name: string] {
    let core_path = ((get-taskservs-path) | path join $name)
    if ($core_path | path exists) {
        $core_path
    } else {
        let extension_taskserv = (get-taskserv $name)
        if ($extension_taskserv | is-not-empty) {
            $extension_taskserv.path
        } else {
            ""
        }
    }
}
