#!/usr/bin/env nu

# Cluster Loader System
# Loads selected clusters into workspace or infrastructure (Layer 2 or Layer 3)

use discover.nu *
use ../lib_provisioning/layers/resolver.nu *

# Load clusters into workspace or infrastructure
export def load-clusters [
    target_path: string,
    clusters: list<string>,
    --force = false  # Overwrite existing
    --level: string = "auto"  # "workspace", "infra", or "auto"
] {
    # Determine target layer
    let layer_info = (determine-layer --workspace $target_path --infra $target_path --level $level)
    let load_path = $layer_info.path

    print $"Loading clusters into ($layer_info.layer) layer: ($load_path)"

    # Validate target path
    if not ($load_path | path exists) {
        error make { msg: $"Target path not found: ($load_path)" }
    }

    # Validate clusters exist in system
    let validation = (validate-clusters $clusters)
    if not $validation.valid {
        error make { msg: $"Missing clusters: ($validation.missing)" }
    }

    # Create clusters directory at target layer
    let clusters_dir = ($load_path | path join ".clusters")
    mkdir $clusters_dir

    # Load each cluster
    let results = ($clusters | each { |name|
        load-single-cluster $load_path $name $force $layer_info.layer
    })

    # Generate imports file
    generate-clusters-imports $load_path $clusters $layer_info.layer

    # Create/update manifest
    update-clusters-manifest $load_path $clusters $layer_info.layer

    {
        target: $load_path
        layer: $layer_info.layer
        loaded: ($results | where status == "success" | get name)
        failed: ($results | where status == "error" | get name)
        summary: $"Loaded (($results | where status == 'success' | length)) of (($clusters | length)) clusters at ($layer_info.layer) layer"
    }
}

# Load a single cluster
def load-single-cluster [target_path: string, name: string, force: bool, layer: string] {
    let result = (do {
        let cluster_info = (get-cluster-info $name)
        let target_dir = ($target_path | path join ".clusters" $name)

        # Check if already exists
        if ($target_dir | path exists) and (not $force) {
            print $"⚠️  Cluster ($name) already loaded at ($layer) layer (add --force flag to overwrite)"
            return {
                name: $name
                status: "skipped"
                message: "already exists"
            }
        }

        # Copy Nickel files and directories
        cp -r $cluster_info.schema_path $target_dir

        print $"✅ Loaded cluster: ($name) (type: ($cluster_info.cluster_type))"
        {
            name: $name
            status: "success"
            path: $target_dir
            version: $cluster_info.version
            type: $cluster_info.cluster_type
            components: $cluster_info.components
        }
    } | complete)

    if $result.exit_code != 0 {
        print $"❌ Failed to load cluster ($name): ($result.stderr)"
        {
            name: $name
            status: "error"
            error: $result.stderr
        }
    } else {
        $result.stdout | from json
    }
}

# Generate clusters.ncl import file
def generate-clusters-imports [target_path: string, clusters: list<string>, layer: string] {
    # Generate individual imports for each cluster
    let imports = ($clusters | each { |name|
        # Check if the cluster main file exists
        let main_file = ($target_path | path join ".clusters" $name ($name + ".ncl"))
        if ($main_file | path exists) {
            $"import .clusters.($name).($name) as ($name)_cluster"
        } else {
            # Fallback to directory-based import
            $"import .clusters.($name) as ($name)_cluster"
        }
    } | str join "\n")

    # Generate schema exports
    let exports = ($clusters | each { |name|
        $"    ($name): ($name)_cluster"
    } | str join ",\n")

    # Create the complete imports file
    let content = $"# Auto-generated cluster imports ($layer) layer
# Generated: (date now | format date '%Y-%m-%d %H:%M:%S')
# Loaded clusters: ($clusters | str join ', ')

($imports)

# Export all loaded cluster schemas
clusters = {
($exports)
}

clusters"

    # Save the imports file
    $content | save -f ($target_path | path join "clusters.ncl")

    # Also create individual alias files for easier direct imports
    for $name in $clusters {
        let alias_content = $"# Cluster alias for ($name)
# Generated: (date now | format date '%Y-%m-%d %H:%M:%S')
# Layer: ($layer)

import .clusters.($name) as ($name)

# Re-export for convenience
($name)"
        $alias_content | save -f ($target_path | path join $"cluster_($name).ncl")
    }
}

# Update clusters manifest
def update-clusters-manifest [target_path: string, clusters: list<string>, layer: string] {
    let manifest_dir = ($target_path | path join ".manifest")
    mkdir $manifest_dir
    let manifest_path = ($manifest_dir | path join "clusters.yaml")
    let existing = if ($manifest_path | path exists) {
        open $manifest_path
    } else {
        {}
    }

    let cluster_entries = ($clusters | each { |name|
        let info = (get-cluster-info $name)
        {
            name: $name
            version: $info.version
            type: $info.cluster_type
            components: $info.components
            layer: $layer
            loaded_at: (date now | format date '%Y-%m-%d %H:%M:%S')
            source_path: $info.schema_path
        }
    })

    let manifest = {
        loaded_clusters: $cluster_entries
        last_updated: (date now | format date '%Y-%m-%d %H:%M:%S')
        target_path: $target_path
        layer: $layer
    }

    $manifest | to yaml | save -f $manifest_path
}

# Remove cluster from workspace
export def unload-cluster [workspace: string, name: string] {
    let target_dir = ($workspace | path join ".clusters" $name)

    if not ($target_dir | path exists) {
        error make { msg: $"Cluster ($name) not loaded in workspace" }
    }

    rm -rf $target_dir

    # Update manifest and imports
    let manifest_path = ($workspace | path join "clusters.manifest.yaml")
    if ($manifest_path | path exists) {
        let manifest = (open $manifest_path)
        let updated_clusters = ($manifest.loaded_clusters | where name != $name)

        if ($updated_clusters | is-empty) {
            rm $manifest_path
            rm ($workspace | path join "clusters.ncl")
        } else {
            let updated_manifest = ($manifest | update loaded_clusters $updated_clusters)
            $updated_manifest | to yaml | save $manifest_path

            # Regenerate imports
            let names = ($updated_clusters | get name)
            # Determine layer from manifest or default to workspace
            let layer = ($manifest.layer? | default "workspace")
            generate-clusters-imports $workspace $names $layer
        }
    }

    print $"✅ Unloaded cluster: ($name)"
    {
        name: $name
        status: "unloaded"
        workspace: $workspace
    }
}

# List loaded clusters in workspace
export def list-loaded-clusters [workspace: string] {
    let manifest_path = ($workspace | path join "clusters.manifest.yaml")

    if not ($manifest_path | path exists) {
        return []
    }

    let manifest = (open $manifest_path)
    $manifest.loaded_clusters? | default []
}

# Clone cluster configuration for customization
export def clone-cluster [
    workspace: string,
    source_name: string,
    target_name: string
] {
    # Check if source cluster is loaded
    let loaded = (list-loaded-clusters $workspace)
    let source_loaded = ($loaded | where name == $source_name | length) > 0

    if not $source_loaded {
        error make { msg: $"Source cluster ($source_name) not loaded in workspace" }
    }

    let source_dir = ($workspace | path join ".clusters" $source_name)
    let target_dir = ($workspace | path join ".clusters" $target_name)

    if ($target_dir | path exists) {
        error make { msg: $"Target cluster ($target_name) already exists" }
    }

    # Copy cluster files
    cp -r $source_dir $target_dir

    # Update cluster name in schema files
    let schema_files = (ls ($target_dir | path join "*.ncl") | get name)
    for $file in $schema_files {
        let content = (open $file)
        let updated = ($content | str replace $source_name $target_name)
        $updated | save $file
    }

    # Update manifest
    let current_clusters = (list-loaded-clusters $workspace | get name)
    let updated_clusters = ($current_clusters | append $target_name)
    # Determine layer from loaded cluster manifests or default to workspace
    let layer = "workspace"  # Default for cloned clusters
    update-clusters-manifest $workspace $updated_clusters $layer

    # Regenerate imports
    generate-clusters-imports $workspace $updated_clusters $layer

    print $"✅ Cloned cluster: ($source_name) → ($target_name)"
    {
        source: $source_name
        target: $target_name
        status: "cloned"
        workspace: $workspace
    }
}
