#!/usr/bin/env nu

# Cluster Discovery System
# Discovers available cluster definitions with metadata extraction

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

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

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

    # Find all cluster directories with Nickel modules
    ls $clusters_path
    | where type == "dir"
    | each { |dir|
        let cluster_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_cluster_metadata $cluster_name $schema_path
        }
    }
    | compact
    | sort-by name
}

# Extract metadata from a cluster's Nickel module
def extract_cluster_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) cluster configuration"
    }

    # Extract cluster components from schema
    let components = extract_cluster_components $main_schema

    # Determine cluster type based on components
    let cluster_type = determine_cluster_type $components

    {
        name: $name
        type: "cluster"
        cluster_type: $cluster_type
        version: $mod_content.package.version
        schema_path: $schema_path
        main_schema: $main_schema
        dependencies: $dependencies
        components: $components
        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
}

# Extract cluster components from schema
def extract_cluster_components [schema_file: string] {
    if not ($schema_file | path exists) {
        return []
    }

    let content = (open $schema_file)

    # Look for component patterns in the schema
    let components = []

    # Check for common component mentions
    let common_components = [
        "kubernetes", "k8s", "cilium", "calico", "nginx", "traefik",
        "prometheus", "grafana", "redis", "postgres", "mysql",
        "buildkit", "registry", "docker", "containerd"
    ]

    $common_components | each { |comp|
        if ($content | str contains $comp) {
            $comp
        }
    } | compact
}

# Determine cluster type based on components
def determine_cluster_type [components: list<string>] {
    if ($components | any { |comp| $comp in ["buildkit", "registry", "docker"] }) {
        "ci-cd"
    } else if ($components | any { |comp| $comp in ["prometheus", "grafana"] }) {
        "monitoring"
    } else if ($components | any { |comp| $comp in ["nginx", "traefik"] }) {
        "web"
    } else if ($components | any { |comp| $comp in ["redis", "postgres", "mysql"] }) {
        "database"
    } else if ($components | any { |comp| $comp in ["kubernetes", "k8s"] }) {
        "orchestration"
    } else {
        "application"
    }
}

# Search clusters by name, type, or components
export def search-clusters [query: string] {
    discover-clusters
    | where (
        ($it.name | str contains $query) or
        ($it.cluster_type | str contains $query) or
        ($it.description | str contains $query) or
        ($it.components | any { |comp| $comp | str contains $query })
    )
}

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

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

    $found
}

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

# Validate cluster availability
export def validate-clusters [names: list<string>] {
    let available = (discover-clusters | 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 clusters that use specific components
export def find-clusters-with-component [component: string] {
    discover-clusters
    | where ($it.components | any { |comp| $comp == $component })
}

# List all available cluster types
export def list-cluster-types [] {
    discover-clusters
    | get cluster_type
    | uniq
    | sort
}
