#!/usr/bin/env nu

# Infrastructure Migration Tool
# Helps migrate existing infrastructures to use the new layered template system

# Extract infrastructure patterns to templates
export def "migrate extract" [
    infra_name: string,        # Source infrastructure (e.g., "wuji")
    --dry-run = false         # Show what would be done without doing it
] {
    print $"🔄 Extracting patterns from ($infra_name) infrastructure"

    let infra_path = $"../../../workspace/infra/($infra_name)"
    let templates_path = "../templates"

    if not ($infra_path | path exists) {
        error make {msg: $"Infrastructure ($infra_name) not found at ($infra_path)"}
    }

    # Extract taskservs
    if ($"($infra_path)/taskservs" | path exists) {
        print "  📦 Extracting taskserv patterns..."
        extract_taskservs $infra_path $templates_path $dry_run
    }

    # Extract provider defaults
    if ($"($infra_path)/defs" | path exists) {
        print "  📦 Extracting provider patterns..."
        extract_providers $infra_path $templates_path $dry_run
    }

    # Extract server patterns
    if ($"($infra_path)/defs/servers.k" | path exists) {
        print "  📦 Extracting server patterns..."
        extract_servers $infra_path $templates_path $dry_run
    }

    if not $dry_run {
        print $"✅ Extraction completed for ($infra_name)"
        print $"📝 Templates created in ($templates_path)"
        print $"Next step: Run 'migrate convert ($infra_name)' to convert infrastructure to use templates"
    } else {
        print $"✅ Dry run completed - no files were created"
    }
}

# Convert infrastructure to use templates
export def "migrate convert" [
    infra_name: string,        # Infrastructure to convert
    --backup = true,           # Create backup before conversion
    --dry-run = false         # Show what would be done
] {
    print $"🔄 Converting ($infra_name) to use template system"

    let infra_path = $"../../../workspace/infra/($infra_name)"

    if not ($infra_path | path exists) {
        error make {msg: $"Infrastructure ($infra_name) not found"}
    }

    if $backup and not $dry_run {
        let backup_path = $"($infra_path).backup-(date now | format date '%Y%m%d_%H%M%S')"
        print $"📁 Creating backup at ($backup_path)"
        cp -r $infra_path $backup_path
    }

    # Convert taskservs to use templates
    convert_taskservs_to_templates $infra_path $infra_name $dry_run

    # Convert provider configs
    convert_providers_to_templates $infra_path $infra_name $dry_run

    if not $dry_run {
        print $"✅ Conversion completed for ($infra_name)"
        print $"🧪 Test with: module-loader-enhanced layer test kubernetes --infra ($infra_name)"
    } else {
        print $"✅ Dry run completed - no files were modified"
    }
}

# Validate template usage in infrastructure
export def "migrate validate" [
    infra_name: string         # Infrastructure to validate
] {
    print $"🔍 Validating template usage in ($infra_name)"

    let infra_path = $"../../../workspace/infra/($infra_name)"
    let issues = []

    if not ($infra_path | path exists) {
        error make {msg: $"Infrastructure ($infra_name) not found"}
    }

    # Check for template imports
    validate_template_imports $infra_path $infra_name

    # Check layer resolution
    validate_layer_resolution $infra_name

    print $"✅ Validation completed for ($infra_name)"
}

# Compare configurations between infrastructures
export def "migrate diff" [
    source_infra: string,      # Source infrastructure
    target_infra: string       # Target infrastructure
] {
    print $"🔍 Comparing ($source_infra) vs ($target_infra)"

    let source_path = $"../../../workspace/infra/($source_infra)"
    let target_path = $"../../../workspace/infra/($target_infra)"

    compare_taskservs $source_path $target_path
    compare_providers $source_path $target_path

    print $"✅ Comparison completed"
}

# === HELPER FUNCTIONS ===

def extract_taskservs [infra_path: string, templates_path: string, dry_run: bool] {
    let taskservs_dir = $"($infra_path)/taskservs"

    if ($taskservs_dir | path exists) {
        for file in (ls $taskservs_dir | where type == file | get name) {
            let filename = ($file | path basename)
            let taskserv_name = ($filename | str replace ".k" "")

            # Determine template category based on taskserv name
            let category = categorize_taskserv $taskserv_name
            let target_dir = $"($templates_path)/taskservs/($category)"
            let target_file = $"($target_dir)/($filename)"

            print $"    ➜ ($taskserv_name) -> ($category)/($filename)"

            if not $dry_run {
                mkdir $target_dir

                # Read original file and convert to template
                let content = open $file
                let template_content = create_taskserv_template $content $taskserv_name
                $template_content | save $target_file
            }
        }
    }
}

def extract_providers [infra_path: string, templates_path: string, dry_run: bool] {
    let defs_dir = $"($infra_path)/defs"

    if ($defs_dir | path exists) {
        for file in (ls $defs_dir | where name =~ "_defaults\.k$" | get name) {
            let filename = ($file | path basename)
            let provider_name = ($filename | str replace "_defaults.k" "")
            let target_dir = $"($templates_path)/providers/($provider_name)"
            let target_file = $"($target_dir)/defaults.k"

            print $"    ➜ ($provider_name) defaults -> providers/($provider_name)/defaults.k"

            if not $dry_run {
                mkdir $target_dir

                # Read and convert to template
                let content = open $file
                let template_content = create_provider_template $content $provider_name
                $template_content | save $target_file
            }
        }
    }
}

def extract_servers [infra_path: string, templates_path: string, dry_run: bool] {
    let servers_file = $"($infra_path)/defs/servers.k"

    if ($servers_file | path exists) {
        print $"    ➜ Extracting server patterns"

        if not $dry_run {
            # Parse servers.k and create templates
            create_server_templates $servers_file $templates_path
        }
    }
}

def convert_taskservs_to_templates [infra_path: string, infra_name: string, dry_run: bool] {
    let taskservs_dir = $"($infra_path)/taskservs"

    if ($taskservs_dir | path exists) {
        print $"  🔧 Converting taskservs to use templates..."

        for file in (ls $taskservs_dir | where type == file | get name) {
            let filename = ($file | path basename)
            let taskserv_name = ($filename | str replace ".k" "")

            print $"    ➜ Converting ($taskserv_name)"

            if not $dry_run {
                # Create new file that uses templates
                let new_content = create_template_based_taskserv $taskserv_name $infra_name
                $new_content | save $file
            }
        }
    }
}

def convert_providers_to_templates [infra_path: string, infra_name: string, dry_run: bool] {
    let defs_dir = $"($infra_path)/defs"

    if ($defs_dir | path exists) {
        print $"  🔧 Converting providers to use templates..."

        for file in (ls $defs_dir | where name =~ "_defaults\.k$" | get name) {
            let filename = ($file | path basename)
            let provider_name = ($filename | str replace "_defaults.k" "")

            print $"    ➜ Converting ($provider_name) defaults"

            if not $dry_run {
                # Create new file that uses templates
                let new_content = create_template_based_provider $provider_name $infra_name
                $new_content | save $file
            }
        }
    }
}

def categorize_taskserv [name: string] -> string {
    match $name {
        $n if ($n | str contains "kubernetes") => "kubernetes"
        $n if ($n | str contains "k8s") => "kubernetes"
        $n if ($n in ["rook-ceph", "mayastor"]) => "storage"
        $n if ($n in ["cilium", "coredns", "proxy"]) => "networking"
        $n if ($n in ["containerd", "crio", "podman", "runc", "crun", "youki"]) => "container-runtime"
        _ => "misc"
    }
}

def create_taskserv_template [content: string, name: string] -> string {
    # Convert existing taskserv to template format
    # This is a simplified version - in practice, you'd parse the KCL properly
    let template_header = $"# ($name | str title-case) Template
# Extracted from infrastructure patterns
# Provides ($name) configuration with customizable defaults

import taskservs.($name).kcl.($name) as ($name)_core
import ../../../workspace/templates/lib/compose as comp

"

    # Add the existing content with template wrapper
    $"($template_header)($content)"
}

def create_provider_template [content: string, provider: string] -> string {
    let template_header = $"# ($provider | str title-case) Provider Template
# Extracted from infrastructure patterns
# Provides ($provider) provider defaults with customizable options

import ($provider)_prov
import ../../../workspace/templates/lib/compose as comp
import ../../../workspace/templates/lib/override as ovr

"

    $"($template_header)($content)"
}

def create_server_templates [servers_file: string, templates_path: string] {
    # Parse servers.k and create control-plane and worker templates
    # This would need more sophisticated KCL parsing

    let servers_content = open $servers_file

    # Create control-plane template
    let cp_template = $"# Control Plane Server Template
# Extracted from server patterns

import upcloud_prov
import ../../../workspace/templates/lib/compose as comp

schema ControlPlaneServer {
    hostname: str
    plan: str = \"2xCPU-4GB\"
    # ... other control plane specific settings
}

control_plane_server = ControlPlaneServer {}"

    mkdir $"($templates_path)/servers"
    $cp_template | save $"($templates_path)/servers/control-plane.k"
}

def create_template_based_taskserv [name: string, infra: string] -> string {
    $"# ($name | str title-case) Configuration for ($infra)
# Uses workspace templates with infrastructure-specific overrides

import ../../../provisioning/workspace/registry/imports as reg
import ../../../provisioning/workspace/templates/lib/compose as comp
import ../../../provisioning/workspace/templates/lib/override as ovr

# Use template with infrastructure-specific overrides
_taskserv = ovr.infrastructure_overrides.taskserv_override (
    reg.tpl_($name)_base.($name)_base,
    \"($infra)\",
    \"($name)\",
    {
        cluster_name: \"($infra)\"
        # Add other infrastructure-specific overrides here
    }
)

_taskserv"
}

def create_template_based_provider [provider: string, infra: string] -> string {
    $"# ($provider | str title-case) Defaults for ($infra)
# Uses workspace templates with infrastructure-specific overrides

import ../../../provisioning/workspace/registry/imports as reg
import ../../../provisioning/workspace/templates/lib/compose as comp
import ../../../provisioning/workspace/templates/lib/override as ovr

# Use template with infrastructure-specific overrides
ovr.infrastructure_overrides.create_infra_config (
    reg.tpl_($provider)_defaults.($provider)_defaults,
    \"($infra)\",
    \"($provider)\",
    \"($infra).local\",  # Update with actual domain
    {
        # Add infrastructure-specific overrides here
    }
)"
}

def validate_template_imports [infra_path: string, infra_name: string] {
    print $"  🔍 Checking template imports..."

    # Check if files use template imports
    let taskservs_dir = $"($infra_path)/taskservs"

    if ($taskservs_dir | path exists) {
        for file in (ls $taskservs_dir | where type == file | get name) {
            let content = open $file
            let has_template_import = ($content | str contains "workspace/templates") or ($content | str contains "workspace/registry/imports")

            let filename = ($file | path basename)
            if $has_template_import {
                print $"    ✅ ($filename) uses templates"
            } else {
                print $"    ⚠️  ($filename) not using templates"
            }
        }
    }
}

def validate_layer_resolution [infra_name: string] {
    print $"  🔍 Validating layer resolution..."

    # Test common taskservs
    let common_taskservs = ["kubernetes", "cilium", "containerd"]

    for taskserv in $common_taskservs {
        let core_exists = ($"../../../provisioning/extensions/taskservs/($taskserv)" | path exists)
        let workspace_exists = ($"../templates/taskservs/($taskserv)" | path exists)
        let infra_exists = ($"../../../workspace/infra/($infra_name)/taskservs/($taskserv).k" | path exists)

        let resolution = []
        if $infra_exists { $resolution = ($resolution | append "infra") }
        if $workspace_exists { $resolution = ($resolution | append "workspace") }
        if $core_exists { $resolution = ($resolution | append "core") }

        if ($resolution | length) > 0 {
            print $"    ✅ ($taskserv): (($resolution | str join ' -> '))"
        } else {
            print $"    ❌ ($taskserv): not found in any layer"
        }
    }
}

def compare_taskservs [source_path: string, target_path: string] {
    print $"  📊 Comparing taskservs..."

    let source_taskservs = if ($"($source_path)/taskservs" | path exists) {
        ls $"($source_path)/taskservs" | get name | each {|f| $f | path basename | str replace ".k" ""}
    } else { [] }

    let target_taskservs = if ($"($target_path)/taskservs" | path exists) {
        ls $"($target_path)/taskservs" | get name | each {|f| $f | path basename | str replace ".k" ""}
    } else { [] }

    let common = $source_taskservs | filter {|t| $t in $target_taskservs}
    let source_only = $source_taskservs | filter {|t| not ($t in $target_taskservs)}
    let target_only = $target_taskservs | filter {|t| not ($t in $source_taskservs)}

    if ($common | length) > 0 {
        print $"    ✅ Common: (($common | str join ', '))"
    }

    if ($source_only | length) > 0 {
        print $"    ➡️  Source only: (($source_only | str join ', '))"
    }

    if ($target_only | length) > 0 {
        print $"    ⬅️  Target only: (($target_only | str join ', '))"
    }
}

def compare_providers [source_path: string, target_path: string] {
    print $"  📊 Comparing providers..."

    let source_providers = if ($"($source_path)/defs" | path exists) {
        ls $"($source_path)/defs" | where name =~ "_defaults\.k$" | get name | each {|f| $f | path basename | str replace "_defaults.k" ""}
    } else { [] }

    let target_providers = if ($"($target_path)/defs" | path exists) {
        ls $"($target_path)/defs" | where name =~ "_defaults\.k$" | get name | each {|f| $f | path basename | str replace "_defaults.k" ""}
    } else { [] }

    let common = $source_providers | filter {|p| $p in $target_providers}
    let source_only = $source_providers | filter {|p| not ($p in $target_providers)}
    let target_only = $target_providers | filter {|p| not ($p in $source_providers)}

    if ($common | length) > 0 {
        print $"    ✅ Common: (($common | str join ', '))"
    }

    if ($source_only | length) > 0 {
        print $"    ➡️  Source only: (($source_only | str join ', '))"
    }

    if ($target_only | length) > 0 {
        print $"    ⬅️  Target only: (($target_only | str join ', '))"
    }
}
