#!/usr/bin/env nu
# Dynamic configuration loader for version management
# Discovers and loads version configurations from the filesystem

use version_core.nu *

# Discover version configurations
export def discover-configurations [
    --base-path: string = ""
    --types: list = []  # Filter by types
]: nothing -> list {
    let base = if ($base_path | is-empty) {
        ($env.PROVISIONING? | default $env.PWD)
    } else { $base_path }
    mut configurations = []

    # Load from known version files directly
    let version_files = [
        ($base | path join "versions.yaml")
        ($base | path join "core" | path join "versions.yaml")
    ]

    for file in $version_files {
        if ($file | path exists) {
            let configs = (load-configuration-file $file)
            if ($configs | is-not-empty) {
                $configurations = ($configurations | append $configs)
            }
        }
    }

    # Also check providers directory
    let providers_path = ($base | path join "providers")
    if ($providers_path | path exists) {
        for provider_dir in (ls $providers_path | get name) {
            let version_file = ($provider_dir | path join "versions.yaml")
            if ($version_file | path exists) {
                let configs = (load-configuration-file $version_file)
                if ($configs | is-not-empty) {
                    $configurations = ($configurations | append $configs)
                }
            }
        }
    }

    # Filter by types if specified
    if ($types | length) > 0 {
        $configurations | where type in $types
    } else {
        $configurations
    }
}

# Load configuration from file
export def load-configuration-file [
    file_path: string
]: nothing -> list {
    if not ($file_path | path exists) { return [] }

    let ext = ($file_path | path parse | get extension)
    let parent_dir = ($file_path | path dirname)
    let context = (extract-context $parent_dir)

    mut configs = []

    match $ext {
        "yaml" | "yml" => {
            let data = (open $file_path)
            if ($data | describe | str contains "record") {
                # Convert record entries to configurations
                for item in ($data | transpose key value) {
                    let config = (create-configuration $item.key $item.value $context $file_path)
                    $configs = ($configs | append $config)
                }
            } else if ($data | describe | str contains "list") {
                # Already a list of configurations
                $configs = $data
            }
        }
        "k" => {
            # Parse KCL files for version information
            let content = (open $file_path)
            let version_data = (extract-kcl-versions $content)
            for item in $version_data {
                let config = (create-configuration $item.name $item $context $file_path)
                $configs = ($configs | append $config)
            }
        }
        "toml" => {
            let data = (open $file_path)
            for section in ($data | transpose key value) {
                if ($section.value | get -o version | is-not-empty) {
                    let config = (create-configuration $section.key $section.value $context $file_path)
                    $configs = ($configs | append $config)
                }
            }
        }
        "json" => {
            let data = (open $file_path)
            if ($data | get -o components | is-not-empty) {
                $configs = $data.components
            } else {
                # Treat as single configuration
                $configs = [$data]
            }
        }
        _ => []
    }

    $configs
}

# Extract context from path
export def extract-context [
    dir_path: string
]: nothing -> record {
    let parts = ($dir_path | split row "/")

    # Determine type based on path structure
    let type = if ($parts | any { |p| $p == "providers" }) {
        "provider"
    } else if ($parts | any { |p| $p == "taskservs" }) {
        "taskserv"
    } else if ($parts | any { |p| $p == "clusters" }) {
        "cluster"
    } else if ($parts | any { |p| $p == "tools" }) {
        "tool"
    } else {
        "generic"
    }

    # Extract category/subcategory
    let category = if $type == "provider" {
        $parts | skip while { |p| $p != "providers" } | skip 1 | first
    } else if $type == "taskserv" {
        $parts | skip while { |p| $p != "taskservs" } | skip 1 | first
    } else {
        ""
    }

    {
        type: $type
        category: $category
        path: $dir_path
    }
}

# Create configuration object
export def create-configuration [
    id: string
    data: record
    context: record
    source_file: string
]: nothing -> record {
    # Build detector configuration
    let detector = if ($data | get -o check_cmd | is-not-empty) {
        {
            method: "command"
            command: $data.check_cmd
            pattern: ($data | get -o parse_pattern | default "")
            capture: ($data | get -o capture_group | default "version")
        }
    } else if ($data | get -o detector | is-not-empty) {
        $data.detector
    } else {
        {}
    }

    # Build source configuration
    let source = if ($data | get -o source | is-not-empty) {
        if ($data.source | str contains "github.com") {
            {
                type: "github"
                repo: ($data.source | parse -r 'github\.com/(?<repo>.+)' | get -o 0 | get -o repo | str replace -r '/(releases|tags).*$' '')
            }
        } else if ($data.source | str starts-with "docker") {
            {
                type: "docker"
                image: ($data.source | str replace "docker://" "")
            }
        } else if ($data.source | str starts-with "http") {
            {
                type: "url"
                url: $data.source
                field: ($data | get -o version_field | default "")
            }
        } else {
            { type: "custom", config: $data.source }
        }
    } else if ($data | get -o tags | is-not-empty) {
        # Infer from tags URL
        if ($data.tags | str contains "github") {
            {
                type: "github"
                repo: ($data.tags | parse -r 'github\.com/(?<repo>[^/]+/[^/]+)' | get -o 0 | get -o repo)
            }
        } else {
            { type: "url", url: $data.tags }
        }
    } else {
        {}
    }

    # Build complete configuration
    {
        id: $id
        type: $context.type
        category: ($context.category | default "")
        version: ($data | get -o version | default "")
        fixed: ($data | get -o fixed | default false)
        source: $source
        detector: $detector
        comparison: ($data | get -o comparison | default "semantic")
        metadata: {
            source_file: $source_file
            site: ($data | get -o site | default "")
            description: ($data | get -o description | default "")
            install_cmd: ($data | get -o install_cmd | default "")
            lib: ($data | get -o lib | default "")
        }
    }
}

# Extract version info from KCL content
export def extract-kcl-versions [
    content: string
]: nothing -> list {
    mut versions = []

    # Look for schema definitions with version fields
    let lines = ($content | lines)
    mut current_schema = ""
    mut current_data = {}

    for line in $lines {
        if ($line | str contains "schema ") {
            # New schema found
            if ($current_schema | is-not-empty) and ($current_data | get -o version | is-not-empty) {
                $versions = ($versions | append {
                    name: $current_schema
                    ...$current_data
                })
            }
            $current_schema = ($line | parse -r 'schema\s+(\w+)' | get -o 0 | get -o 0 | default "")
            $current_data = {}
        } else if ($line | str contains "version:") or ($line | str contains "version =") {
            # Extract version
            let version = ($line | parse -r 'version[:\s=]+"?([^"]+)"?' | get -o 0 | get -o 0 | default "")
            if ($version | is-not-empty) {
                $current_data.version = $version
            }
        }
    }

    # Add last schema if valid
    if ($current_schema | is-not-empty) and ($current_data | get -o version | is-not-empty) {
        $versions = ($versions | append {
            name: $current_schema
            ...$current_data
        })
    }

    $versions
}