#!/usr/bin/env nu

# Provider Discovery System
# Discovers available cloud providers with metadata extraction

use ../lib_provisioning/config/accessor.nu config-get

# Discover all available providers
export def discover-providers [] {
    # Get absolute path to extensions directory from config
    let providers_path = (config-get "paths.providers" | path expand)

    if not ($providers_path | path exists) {
        error make { msg: $"Providers path not found: ($providers_path)" }
    }

    # Find all provider directories with Nickel modules
    ls $providers_path
    | where type == "dir"
    | each { |dir|
        let provider_name = ($dir.name | path basename)
        let schema_path = ($dir.name | path join "nickel")
        let mod_path = ($schema_path | path join "nickel.mod")

        if ($mod_path | path exists) {
            extract_provider_metadata $provider_name $schema_path
        }
    }
    | compact
    | sort-by name
}

# Extract metadata from a provider's Nickel module
def extract_provider_metadata [name: string, schema_path: string] {
    let mod_path = ($schema_path | path join "nickel.mod")
    let mod_content = (open $mod_path | from toml)

    # Find Nickel schema files
    let schema_files = (glob ($schema_path | path join "*.ncl"))
    let main_schema = ($schema_files | where ($it | str contains $name) | first | default "")

    # Extract dependencies
    let dependencies = ($mod_content.dependencies? | default {} | columns)

    # Get description from schema file if available
    let description = if ($main_schema != "") {
        extract_schema_description $main_schema
    } else {
        $"($name | str title-case) cloud provider"
    }

    # Determine provider type
    let provider_type = match $name {
        "aws" => "cloud"
        "upcloud" => "cloud"
        "gcp" => "cloud"
        "azure" => "cloud"
        "local" => "local"
        _ => "unknown"
    }

    {
        name: $name
        type: "provider"
        provider_type: $provider_type
        version: $mod_content.package.version
        schema_path: $schema_path
        main_schema: $main_schema
        dependencies: $dependencies
        description: $description
        available: true
        last_updated: (ls $mod_path | get 0.modified)
    }
}

# Extract description from Nickel schema file
def extract_schema_description [schema_file: string] {
    if not ($schema_file | path exists) {
        return ""
    }

    # Read first few lines to find description
    let content = (open $schema_file | lines | take 10)
    let description_lines = ($content | where ($it | str starts-with "# ") | take 3)

    if ($description_lines | is-empty) {
        return ""
    }

    $description_lines
    | str replace "^# " ""
    | str join " "
    | str trim
}

# Search providers by name or type
export def search-providers [query: string] {
    discover-providers
    | where ($it.name | str contains $query) or ($it.provider_type | str contains $query) or ($it.description | str contains $query)
}

# Get specific provider info
export def get-provider-info [name: string] {
    let providers = (discover-providers)
    let found = ($providers | where name == $name | first)

    if ($found | is-empty) {
        error make { msg: $"Provider '($name)' not found" }
    }

    $found
}

# List providers by type
export def list-providers-by-type [type: string] {
    discover-providers
    | where provider_type == $type
}

# Validate provider availability
export def validate-providers [names: list<string>] {
    let available = (discover-providers | get name)
    let missing = ($names | where ($it not-in $available))
    let found = ($names | where ($it in $available))

    {
        requested: $names
        found: $found
        missing: $missing
        valid: ($missing | is-empty)
    }
}

# Get default provider (first cloud provider found)
export def get-default-provider [] {
    let cloud_providers = (list-providers-by-type "cloud")

    if ($cloud_providers | is-empty) {
        "local"
    } else {
        $cloud_providers | first | get name
    }
}
