#!/usr/bin/env nu

# Workspace Initialization Tool
# Creates new workspace with proper directory structure for KCL package and module loader systems

use ../core/nulib/lib_provisioning/config/accessor.nu *

# Get dependency configuration (interactive or from flags)
def get-dependency-config [
    workspace_path: string
    dep_option?: string
    dep_url?: string
]: nothing -> record {
    # If dep_option provided, use it; otherwise prompt
    let option = if ($dep_option | is-not-empty) {
        $dep_option
    } else {
        print "\n📦 Provisioning Dependency Configuration"
        print "  Choose how to configure the provisioning package dependency:\n"
        print "  1. workspace-home (default) - Install in workspace .kcl directory (self-contained)"
        print "  2. home-package - Use ~/.kcl/packages/provisioning (shared across workspaces)"
        print "  3. git-package - Use Git repository"
        print "  4. publish-repo - Use KCL registry\n"

        let choice = (input "  Select option [1-4] (default: 1): ")
        let normalized_choice = if ($choice | is-empty) { "1" } else { $choice }

        match $normalized_choice {
            "1" => "workspace-home",
            "2" => "home-package",
            "3" => "git-package",
            "4" => "publish-repo",
            "workspace-home" => "workspace-home",
            "home-package" => "home-package",
            "git-package" => "git-package",
            "publish-repo" => "publish-repo",
            _ => {
                print $"  ⚠️  Invalid choice '($normalized_choice)', using default: workspace-home"
                "workspace-home"
            }
        }
    }

    # Handle each option
    match $option {
        "workspace-home" => {
            print "  ✓ Using workspace-local provisioning package"

            # Always run install - it will check version and update if needed
            install-workspace-provisioning $workspace_path

            {
                type: "workspace-home"
                path: ".kcl/packages/provisioning"
                version: "0.0.1"
            }
        },
        "home-package" => {
            print "  ✓ Using home directory provisioning package"

            # Always run install - it will check version and update if needed
            install-home-provisioning

            {
                type: "home-package"
                path: "~/.kcl/packages/provisioning"
                version: "0.0.1"
            }
        },
        "git-package" => {
            let git_url = if ($dep_url | is-not-empty) {
                $dep_url
            } else {
                input "  Enter Git repository URL: "
            }
            print $"  ✓ Using Git repository: ($git_url)"
            {
                type: "git-package"
                git: $git_url
                version: "0.0.1"
            }
        },
        "publish-repo" => {
            let repo_url = if ($dep_url | is-not-empty) {
                $dep_url
            } else {
                input "  Enter KCL registry URL (or leave empty for default): "
            }
            if ($repo_url | is-not-empty) {
                print $"  ✓ Using registry: ($repo_url)"
                {
                    type: "publish-repo"
                    registry: $repo_url
                    version: "0.0.1"
                }
            } else {
                print "  ✓ Using default KCL registry"
                {
                    type: "publish-repo"
                    version: "0.0.1"
                }
            }
        },
        _ => {
            print $"  ⚠️  Unknown option '($option)', using workspace-home"
            {
                type: "workspace-home"
                path: ".kcl/packages/provisioning"
                version: "0.0.1"
            }
        }
    }
}

# Install provisioning package to workspace .kcl directory
def install-workspace-provisioning [workspace_path: string]: nothing -> nothing {
    let workspace_abs = ($workspace_path | path expand)
    let workspace_kcl_dir = ($workspace_abs | path join ".kcl" "packages")
    let workspace_prov_dir = ($workspace_kcl_dir | path join "provisioning")

    # Create .kcl/packages directory
    mkdir $workspace_kcl_dir

    # Determine source path for provisioning/kcl
    # Try to find provisioning root
    let script_dir = ($env.FILE_PWD? | default (pwd))
    let provisioning_root = ($script_dir | path dirname | path dirname)
    let kcl_source = ($provisioning_root | path join "kcl")

    # Check if source exists
    if not ($kcl_source | path exists) {
        # Try alternative: check if PROVISIONING env var is set
        let alt_source_result = (do {
            let config = (get-config)
            let base_path = ($config.paths.base? | default "")
            if ($base_path | is-not-empty) {
                $base_path | path join "kcl"
            } else {
                ""
            }
        } | complete)

        let alt_source = if $alt_source_result.exit_code != 0 {
            ""
        } else {
            $alt_source_result.stdout
        }

        if ($alt_source | is-not-empty) and ($alt_source | path exists) {
            # Check version and update if needed
            if (check-and-update-package $workspace_prov_dir $alt_source) {
                print $"  📋 Copying provisioning KCL package from: ($alt_source)"
                cp -r $alt_source $workspace_prov_dir
            }
        } else {
            error make {
                msg: $"Cannot find provisioning KCL package. Tried: ($kcl_source), ($alt_source)"
            }
        }
    } else {
        # Check version and update if needed
        if (check-and-update-package $workspace_prov_dir $kcl_source) {
            print $"  📋 Copying provisioning KCL package from: ($kcl_source)"
            cp -r $kcl_source $workspace_prov_dir
        }

        # Also create distribution package for sharing/reuse
        build-distribution-package $provisioning_root $kcl_source
    }

    print $"  ✅ Provisioning package ready at: ($workspace_prov_dir)"
}

# Install provisioning package to home .kcl directory
def install-home-provisioning []: nothing -> nothing {
    let home_kcl_dir = ($env.HOME | path join ".kcl" "packages")
    let home_prov_dir = ($home_kcl_dir | path join "provisioning")

    # Create .kcl/packages directory
    mkdir $home_kcl_dir

    # Determine source path for provisioning/kcl
    # Try to find provisioning root
    let script_dir = ($env.FILE_PWD? | default (pwd))
    let provisioning_root = ($script_dir | path dirname | path dirname)
    let kcl_source = ($provisioning_root | path join "kcl")

    # Check if source exists
    if not ($kcl_source | path exists) {
        # Try alternative: check if PROVISIONING env var is set
        let alt_source_result = (do {
            let config = (get-config)
            let base_path = ($config.paths.base? | default "")
            if ($base_path | is-not-empty) {
                $base_path | path join "kcl"
            } else {
                ""
            }
        } | complete)

        let alt_source = if $alt_source_result.exit_code != 0 {
            ""
        } else {
            $alt_source_result.stdout
        }

        if ($alt_source | is-not-empty) and ($alt_source | path exists) {
            # Check version and update if needed
            if (check-and-update-package $home_prov_dir $alt_source) {
                print $"  📋 Copying provisioning KCL package from: ($alt_source)"
                cp -r $alt_source $home_prov_dir
            }
        } else {
            error make {
                msg: $"Cannot find provisioning KCL package. Tried: ($kcl_source), ($alt_source)"
            }
        }
    } else {
        # Check version and update if needed
        if (check-and-update-package $home_prov_dir $kcl_source) {
            print $"  📋 Copying provisioning KCL package from: ($kcl_source)"
            cp -r $kcl_source $home_prov_dir
        }

        # Also create distribution package for sharing/reuse
        build-distribution-package $provisioning_root $kcl_source
    }

    print $"  ✅ Provisioning package ready at: ($home_prov_dir)"
}

# Check package version and determine if update is needed
# Returns true if package should be copied/updated, false if already up to date
def check-and-update-package [
    target_dir: string
    source_dir: string
]: nothing -> bool {
    # If target doesn't exist, needs installation
    if not ($target_dir | path exists) {
        print $"  📦 Installing new provisioning package..."
        return true
    }

    # Get source version
    let source_version = get-kcl-version $source_dir

    # Get installed version
    let installed_version = get-kcl-version $target_dir

    # Compare versions
    if $source_version != $installed_version {
        print $"  🔄 Updating provisioning package: ($installed_version) → ($source_version)"
        print $"  🗑️  Removing old version..."
        rm -rf $target_dir
        return true
    } else {
        print $"  ✓ Provisioning package already up to date (v($installed_version))"
        return false
    }
}

# Get KCL package version from kcl.mod file
def get-kcl-version [kcl_path: string]: nothing -> string {
    let kcl_mod = ($kcl_path | path join "kcl.mod")

    if not ($kcl_mod | path exists) {
        return "unknown"
    }

    let result = (do {
        let mod_content = (open $kcl_mod | from toml)
        $mod_content.package?.version? | default "unknown"
    } | complete)

    if $result.exit_code != 0 {
        "unknown"
    } else {
        $result.stdout
    }
}

# Build distribution package from KCL source
def build-distribution-package [provisioning_root: string, kcl_source: string]: nothing -> nothing {
    let dist_dir = ($provisioning_root | path join "distribution" "packages")
    let registry_dir = ($provisioning_root | path join "distribution" "registry")

    # Create distribution directories
    mkdir $dist_dir
    mkdir $registry_dir

    # Generate package info
    let version_result = (do {
        let kcl_mod = ($kcl_source | path join "kcl.mod")
        if ($kcl_mod | path exists) {
            let mod_content = (open $kcl_mod | from toml)
            $mod_content.package?.version? | default "0.0.1"
        } else {
            "0.0.1"
        }
    } | complete)

    let version = if $version_result.exit_code != 0 {
        "0.0.1"
    } else {
        $version_result.stdout
    }

    let package_name = $"provisioning-kcl-($version).tar.gz"
    let package_path = ($dist_dir | path join $package_name)

    # Check if package already exists and is up to date
    if ($package_path | path exists) {
        let pkg_time = (ls $package_path | get 0.modified)
        let src_time = (ls $kcl_source | sort-by modified -r | get 0.modified)

        if $pkg_time > $src_time {
            print $"  ℹ️  Distribution package is up to date: ($package_name)"
            return
        }
    }

    print $"  📦 Building distribution package: ($package_name)"

    # Create temporary staging directory
    let staging_dir = ($dist_dir | path join ".staging")
    mkdir $staging_dir
    let staging_prov = ($staging_dir | path join "provisioning")

    # Copy KCL files to staging
    cp -r $kcl_source $staging_prov

    # Create README for distribution
    let readme_content = $"# Provisioning KCL Package

Version: ($version)
Generated: (date now | format date '%Y-%m-%d %H:%M:%S')

## Installation

### Option 1: Workspace-local installation
Copy this package to your workspace:
```bash
cp -r provisioning /path/to/workspace/.kcl/packages/
```

### Option 2: User-level installation
Install to your home directory:
```bash
mkdir -p ~/.kcl/packages
cp -r provisioning ~/.kcl/packages/
```

### Option 3: Using workspace init
When initializing a workspace, choose 'workspace-home' option:
```bash
provisioning ws init myworkspace
# Select option 1 \(workspace-home\)
```

## Usage

In your KCL files:
```kcl
import provisioning.settings as settings
import provisioning.server as server
import provisioning.defaults as defaults
```

## Contents

This package contains the core provisioning KCL schemas including:
- settings.k - Main settings schema
- server.k - Server configuration schema
- defaults.k - Default values and constants
- And other core schemas

For more information, visit the provisioning documentation.
"

    $readme_content | save ($staging_dir | path join "README.md")

    # Create package archive
    let tar_result = (do {
        cd $staging_dir
        tar czf $package_path provisioning README.md
        cd $dist_dir  # Go back before cleanup
    } | complete)

    if $tar_result.exit_code != 0 {
        print $"  ⚠️  Warning: Could not create distribution package: ($tar_result.stderr)"
        # Try cleanup anyway
        let cleanup_result = (do { rm -rf $staging_dir } | complete)
    } else {
        print $"  ✅ Created distribution package: ($package_path)"

        # Update registry
        update-package-registry $registry_dir $package_name $version $kcl_source

        # Clean up staging
        rm -rf $staging_dir
    }
}

# Update package registry with metadata
def update-package-registry [
    registry_dir: string
    package_name: string
    version: string
    source_path: string
]: nothing -> nothing {
    let registry_file = ($registry_dir | path join "packages.json")

    # Load existing registry or create new
    let registry = if ($registry_file | path exists) {
        open $registry_file | from json
    } else {
        { packages: [] }
    }

    # Create package entry
    let package_entry = {
        name: "provisioning"
        version: $version
        package_file: $package_name
        created_at: (date now | format date '%Y-%m-%d %H:%M:%S')
        source_path: $source_path
        type: "kcl-package"
        description: "Core provisioning KCL schemas and modules"
    }

    # Update or add package entry
    let updated_packages = (
        $registry.packages
        | where name != "provisioning" or version != $version
        | append $package_entry
    )

    let updated_registry = { packages: $updated_packages }

    # Save registry
    $updated_registry | to json | save -f $registry_file
    print $"  📋 Updated package registry: ($registry_file)"
}

# Load default modules to infrastructure layer
def load-default-modules [workspace_path: string, infra_path: string]: nothing -> nothing {
    let workspace_abs = ($workspace_path | path expand)
    let infra_abs = ($infra_path | path expand)

    # Determine provisioning root and module loader script
    let script_dir = ($env.FILE_PWD? | default (pwd))
    let provisioning_root = ($script_dir | path dirname)
    let module_loader = ($provisioning_root | path join "core" "cli" "module-loader")

    # Verify module loader exists
    if not ($module_loader | path exists) {
        print $"  ⚠️  Warning: Module loader not found at ($module_loader)"
        print $"  💡 You can load modules manually: cd infra/<name> && provisioning mod load taskservs . os"
        return
    }

    # Load os taskserv to infrastructure layer
    let taskserv_result = (do {
        print $"  📦 Loading os taskserv to infrastructure layer..."
        ^nu $module_loader "load" "taskservs" $infra_abs "os"
        print $"  ✅ Loaded os taskserv"
    } | complete)

    if $taskserv_result.exit_code != 0 {
        print $"  ⚠️  Warning: Could not load os taskserv: ($taskserv_result.stderr)"
        print $"  💡 You can load it manually: cd ($infra_path) && provisioning mod load taskservs . os"
    }
}

# Main workspace initialization command
def main [
    workspace_path: string
    --infra-name: string           # Infrastructure name
    --template: string             # Template type: minimal, full, example
    --workspace-type: string       # Workspace type: development, staging, production
    --user-name: string            # User name for workspace
    --taskservs: list<string>      # Taskservs to load during init
    --providers: list<string>      # Providers to load during init
    --clusters: list<string>       # Clusters to load during init
    --dep-option: string           # Dependency option: home-package, git-package, publish-repo, workspace-home
    --dep-url: string              # Dependency URL for git-package or publish-repo
    --overwrite                    # Overwrite existing workspace
    --check                        # Check mode only (dry-run)
] {
    # Validate workspace name - no hyphens allowed (causes KCL module resolution issues)
    let workspace_name = ($workspace_path | path basename)
    if ($workspace_name | str contains "-") {
        print $"❌ Error: Workspace name cannot contain hyphens: '($workspace_name)'"
        print ""
        print "   Hyphens in workspace names cause KCL module resolution issues."
        print $"   Use underscores instead: '($workspace_name | str replace -a '-' '_')'"
        print ""
        exit 1
    }

    # Validate infra name if provided - no hyphens allowed
    if ($infra_name | is-not-empty) and ($infra_name | str contains "-") {
        print $"❌ Error: Infrastructure name cannot contain hyphens: '($infra_name)'"
        print ""
        print "   Hyphens in infrastructure names cause KCL module resolution issues."
        print $"   Use underscores instead: '($infra_name | str replace -a '-' '_')'"
        print ""
        exit 1
    }

    if $check {
        let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" }
        let template_to_use = if ($template | is-not-empty) { $template } else { "minimal" }
        print $"🔍 [CHECK MODE] Would initialize workspace: ($workspace_path)"
        print $"  Template: ($template_to_use)"
        print $"  Type: ($workspace_type | default 'development')"
        print $"  Infrastructure directory: infra/($infra_dir_name)"
        print ""
        print "  Structure to create:"
        print $"    ($workspace_path)/"
        print "      ├── infra/"
        print $"      │   └── ($infra_dir_name)/"
        print "      │       ├── .taskservs/"
        print "      │       ├── .providers/"
        print "      │       ├── .clusters/"
        print "      │       ├── .manifest/"
        print "      │       ├── kcl.mod"
        print "      │       └── servers.k"
        print "      ├── data/"
        print "      ├── tmp/"
        print "      └── resources/"
        if not ($taskservs | is-empty) {
            print ""
            print $"  Taskservs to load: ($taskservs | str join ', ')"
        }
        if not ($providers | is-empty) {
            print $"  Providers to load: ($providers | str join ', ')"
        }
        if not ($clusters | is-empty) {
            print $"  Clusters to load: ($clusters | str join ', ')"
        }
        return
    }

    let workspace_abs = ($workspace_path | path expand)

    # Check if workspace already exists
    if ($workspace_abs | path exists) and not $overwrite {
        print $"❌ Workspace already exists: ($workspace_path)"
        print "   Use --overwrite to overwrite existing workspace"
        exit 1
    }

    print $"🚀 Initializing workspace: ($workspace_path)"

    let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" }
    let template_to_use = if ($template | is-not-empty) { $template } else { "minimal" }

    # Determine provisioning dependency configuration
    let dep_config = get-dependency-config $workspace_abs $dep_option $dep_url

    # Create workspace directory structure
    let workspace_info = create-workspace-structure $workspace_path $infra_dir_name

    # Create basic configuration files
    create-workspace-config $workspace_path $workspace_info.infra_path $infra_dir_name $dep_config

    # Create example files from template
    create-workspace-examples $workspace_path $workspace_info.infra_path $infra_dir_name $template_to_use

    # Load default os taskserv module to infrastructure
    print ""
    print "📦 Loading default modules..."
    load-default-modules $workspace_path $workspace_info.infra_path

    print ""
    print $"✅ Workspace initialized successfully: ($workspace_path)"
    print $"📁 Workspace structure created"
    print $"📂 Infrastructure created: infra/($infra_dir_name)"
    print $"📋 Template applied: ($template_to_use)"
    print $"📄 Configuration files created"
    print $"📦 Default modules loaded: os taskserv"
    print ""
    print "Next steps:"
    print $"  1. cd ($workspace_path)/infra/($infra_dir_name)"
    print "  2. Edit servers.k to customize your infrastructure"
    print "  3. Load additional modules:"
    print "     - provisioning dt  # Discover available taskservs"
    print "     - cd <workspace>/infra/<name> && provisioning mod load taskservs . <name>"
    print $"  4. Deploy: provisioning s create --infra ($infra_dir_name)"
    print ""
    print "Quick start:"
    print $"  cd ($workspace_path)/infra/($infra_dir_name)"
    print "  kcl run servers.k  # Validate configuration"
}

# Create workspace directory structure
def create-workspace-structure [
    workspace_path: string
    infra_name: string
]: nothing -> record {
    let workspace_abs = ($workspace_path | path expand)
    let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" }

    # Create workspace-level directories (non-infrastructure)
    mkdir $workspace_abs
    mkdir ($workspace_abs | path join "data")
    mkdir ($workspace_abs | path join "tmp")
    mkdir ($workspace_abs | path join "resources")

    # Create Layer 2 (workspace-level) module directories
    mkdir ($workspace_abs | path join ".taskservs")
    mkdir ($workspace_abs | path join ".providers")
    mkdir ($workspace_abs | path join ".clusters")
    mkdir ($workspace_abs | path join ".manifest")

    # Create infrastructure directory structure
    let infra_path = ($workspace_abs | path join "infra" | path join $infra_dir_name)
    mkdir $infra_path

    # Create Layer 3 (infrastructure-level) module directories
    mkdir ($infra_path | path join ".taskservs")
    mkdir ($infra_path | path join ".providers")
    mkdir ($infra_path | path join ".clusters")
    mkdir ($infra_path | path join ".manifest")

    # Create module-loader expected directories
    mkdir ($infra_path | path join "taskservs")
    mkdir ($infra_path | path join "overrides")
    mkdir ($infra_path | path join "defs")
    mkdir ($infra_path | path join "config")

    {
        path: $workspace_abs
        infra_path: $infra_path
        infra_name: $infra_dir_name
        created: (date now | format date "%Y-%m-%d %H:%M:%S")
        workspace_dirs: ["data", "tmp", "resources"]
        workspace_modules: [".taskservs", ".providers", ".clusters", ".manifest"]
        infra_dirs: [".taskservs", ".providers", ".clusters", ".manifest"]
    }
}

# Create basic workspace configuration files
def create-workspace-config [
    workspace_path: string
    infra_path: string
    infra_name: string
    dep_config: record
]: nothing -> nothing {
    let workspace_abs = ($workspace_path | path expand)

    # Generate dependency line based on configuration
    let dep_line = match $dep_config.type {
        "workspace-home" => {
            $"provisioning = \{ path = \"../../($dep_config.path)\", version = \"($dep_config.version)\" \}"
        },
        "home-package" => {
            $"provisioning = \{ path = \"($dep_config.path)\", version = \"($dep_config.version)\" \}"
        },
        "git-package" => {
            $"provisioning = \{ git = \"($dep_config.git)\", version = \"($dep_config.version)\" \}"
        },
        "publish-repo" => {
            if ($dep_config.registry? | is-not-empty) {
                $"provisioning = \{ registry = \"($dep_config.registry)\", version = \"($dep_config.version)\" \}"
            } else {
                $"provisioning = \{ version = \"($dep_config.version)\" \}"
            }
        },
        _ => {
            $"provisioning = \{ path = \"~/.kcl/packages/provisioning\", version = \"0.0.1\" \}"
        }
    }

    # Create kcl.mod in infra directory
    let kcl_mod_content = $"[package]
name = \"($infra_name)\"
edition = \"v0.11.3\"
version = \"0.0.1\"

[dependencies]
# Provisioning package dependency \(configured during workspace init\)
($dep_line)
"

    $kcl_mod_content | save ($infra_path | path join "kcl.mod")

    # Create .gitignore at workspace root
    let base_gitignore = "# Workspace runtime data
data/
tmp/
*.log

# Infrastructure module directories (managed by module-loader)
infra/**/.taskservs/
infra/**/.providers/
infra/**/.clusters/
infra/**/.manifest/

# Generated files
infra/**/taskservs.k
infra/**/providers.k
infra/**/clusters.k

# Secrets and sensitive data
*.age
*.enc
*.key
"

    # Add .kcl to gitignore if using workspace-home
    let gitignore_content = if $dep_config.type == "workspace-home" {
        $"($base_gitignore)
# Workspace-local KCL packages \(managed by workspace init\)
.kcl/
"
    } else {
        $base_gitignore
    }

    $gitignore_content | save ($workspace_abs | path join ".gitignore")

    # Create empty manifest files in infra directory
    let empty_manifest = {
        loaded_taskservs: []
        loaded_providers: []
        loaded_clusters: []
        last_updated: (date now | format date "%Y-%m-%d %H:%M:%S")
        infra_path: $infra_path
    }

    $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "taskservs.yaml")
    $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "providers.yaml")
    $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "clusters.yaml")
}

# Load template file
def load-template [
    template_name: string
    file_name: string
]: nothing -> string {
    # Try to find provisioning root
    let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
    let template_path = ($provisioning_root | path join "templates" "workspace" $template_name $file_name)

    if ($template_path | path exists) {
        open $template_path
    } else {
        # Return empty string if template not found (will use fallback)
        ""
    }
}

# Create example workspace files
def create-workspace-examples [
    workspace_path: string
    infra_path: string
    infra_name: string
    template_name: string = "minimal"
]: nothing -> nothing {
    let workspace_abs = ($workspace_path | path expand)

    # Load servers.k template
    let servers_template = load-template $template_name "servers.k"
    let servers_example = if ($servers_template | is-not-empty) {
        $servers_template
    } else {
        # Fallback to minimal template if template not found
        load-template "minimal" "servers.k"
    }

    $servers_example | save ($infra_path | path join "servers.k")

    # Load template README if available
    let template_readme = load-template $template_name "README.md"

    # Create workspace README using simple string concatenation
    let ws_name = ($workspace_path | path basename)

    # Use simple string interpolation for README content
    let readme_content = $"# Workspace: ($ws_name)

This workspace was initialized with the provisioning workspace system.

## Structure

```
($ws_name)/
├── .taskservs/               # Layer 2: Workspace-shared taskserv modules
├── .providers/               # Layer 2: Workspace-shared provider modules
├── .clusters/                # Layer 2: Workspace-shared cluster modules
├── .manifest/                # Layer 2: Workspace-level manifests
├── infra/                    # Infrastructure definitions
│   └── ($infra_name)/        # Infrastructure: ($infra_name)
│       ├── .taskservs/       # Layer 3: Infrastructure-specific overrides
│       ├── .providers/       # Layer 3: Infrastructure-specific overrides
│       ├── .clusters/        # Layer 3: Infrastructure-specific overrides
│       ├── .manifest/        # Layer 3: Infrastructure-level manifests
│       ├── kcl.mod           # KCL module configuration
│       └── servers.k         # Server configuration
├── data/                     # Workspace-level runtime data
├── tmp/                      # Temporary files and deployment artifacts
└── resources/                # Workspace-level resources and templates
```

### 3-Layer Module Architecture

The workspace uses a 3-layer module resolution system:

1. **Layer 1 - System**: Global extensions in provisioning/extensions/
2. **Layer 2 - Workspace**: Shared modules in workspace .taskservs/, .providers/, .clusters/
3. **Layer 3 - Infrastructure**: Infrastructure-specific overrides in infra/<name>/.taskservs/, .providers/, .clusters/

**Resolution order**: Layer 3 → Layer 2 → Layer 1 - higher layers override lower

### Infrastructure Directory

Each infrastructure in infra/<name>/ can:
- Inherit shared modules from workspace layer -Layer 2-
- Override with infrastructure-specific versions -Layer 3-
- Define infrastructure-specific configuration -kcl.mod, servers.k-

## Usage

### 1. Navigate to Infrastructure Directory

Use cd to navigate to your infrastructure directory.

### 2. Load Required Modules

**Option A: Load at workspace level - shared across all infrastructures**

Load shared modules at workspace level using provisioning mod load with --level workspace flag.

**Option B: Load at infrastructure level - specific to one infrastructure**

Load infrastructure-specific modules using provisioning mod load with --level infra flag.

### 3. Verify Module Loading

Use provisioning mod list to verify loaded modules.

### 4. Configure Infrastructure

Edit servers.k in the infrastructure directory to define your requirements. The loaded modules will be available for import.

### 5. Deploy Infrastructure

Use kcl run to generate configuration and provisioning s create to deploy.

## Multiple Infrastructures

You can have multiple infrastructure configurations in one workspace by running workspace init with different --infra names.

## Module Management

- Use 'provisioning mod discover <type>' to find available modules
- Use 'provisioning mod load <type> <infra-path> <modules...>' to load modules
- Use 'provisioning mod unload <type> <infra-path> <module>' to remove modules
- Module manifests track all loaded modules in each infra/<name>/.manifest/

The module directories -.taskservs/, .providers/, .clusters/- are managed automatically and should not be edited manually.
"

    # Combine workspace README with template README
    let final_readme = if ($template_readme | is-not-empty) {
        $"($readme_content)\n\n---\n\n($template_readme)"
    } else {
        $readme_content
    }

    $final_readme | save ($workspace_abs | path join "README.md")

    # Also save template-specific README in infra directory if available
    if ($template_readme | is-not-empty) {
        $template_readme | save ($infra_path | path join "README.md")
    }
}

# Initialize workspace with specific modules
export def "main init" [
    workspace_path: string
    --infra-name: string           # Infrastructure name
    --template: string             # Template type: minimal, full, example
    --workspace-type: string       # Workspace type: development, staging, production
    --user-name: string            # User name for workspace
    --taskservs: list<string> = [] # Taskservs to load during initialization
    --providers: list<string> = [] # Providers to load during initialization
    --clusters: list<string> = []  # Clusters to load during initialization
    --dep-option: string           # Dependency option: home-package, git-package, publish-repo, workspace-home
    --dep-url: string              # Dependency URL for git-package or publish-repo
    --overwrite                    # Overwrite existing workspace
    --check                        # Check mode only (dry-run)
]: nothing -> nothing {
    # Create basic workspace first
    main $workspace_path --infra-name $infra_name --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url --overwrite=$overwrite --check=$check

    # Skip module loading in check mode
    if $check {
        return
    }

    # Load specified modules
    if not ($taskservs | is-empty) {
        print $"Loading taskservs: ($taskservs | str join ', ')"
        ../core/cli/module-loader load taskservs $workspace_path $taskservs
    }

    if not ($providers | is-empty) {
        print $"Loading providers: ($providers | str join ', ')"
        ../core/cli/module-loader load providers $workspace_path $providers
    }

    if not ($clusters | is-empty) {
        print $"Loading clusters: ($clusters | str join ', ')"
        ../core/cli/module-loader load clusters $workspace_path $clusters
    }

    print $"✅ Workspace initialized with modules"
}

# Show workspace information
export def "main info" [workspace_path: string]: nothing -> record {
    let workspace_abs = ($workspace_path | path expand)

    if not ($workspace_abs | path exists) {
        error make { msg: $"Workspace does not exist: ($workspace_abs)" }
    }

    let taskservs_result = (do {
        open ($workspace_abs | path join ".manifest" | path join "taskservs.yaml")
    } | complete)
    let taskservs_manifest = if $taskservs_result.exit_code != 0 {
        { loaded_taskservs: [] }
    } else {
        $taskservs_result.stdout
    }

    let providers_result = (do {
        open ($workspace_abs | path join ".manifest" | path join "providers.yaml")
    } | complete)
    let providers_manifest = if $providers_result.exit_code != 0 {
        { loaded_providers: [] }
    } else {
        $providers_result.stdout
    }

    let clusters_result = (do {
        open ($workspace_abs | path join ".manifest" | path join "clusters.yaml")
    } | complete)
    let clusters_manifest = if $clusters_result.exit_code != 0 {
        { loaded_clusters: [] }
    } else {
        $clusters_result.stdout
    }

    {
        workspace: $workspace_abs
        taskservs_count: ($taskservs_manifest.loaded_taskservs | length)
        providers_count: ($providers_manifest.loaded_providers | length)
        clusters_count: ($clusters_manifest.loaded_clusters | length)
        taskservs: ($taskservs_manifest.loaded_taskservs | get name)
        providers: ($providers_manifest.loaded_providers | get name)
        clusters: ($clusters_manifest.loaded_clusters | get name)
    }
}

# Validate workspace structure
export def "main validate" [workspace_path: string]: nothing -> record {
    let workspace_abs = ($workspace_path | path expand)

    let required_dirs = [".taskservs", ".providers", ".clusters", ".manifest"]
    let required_files = ["kcl.mod", "servers.k"]

    let missing_dirs = $required_dirs | where {|dir|
        not (($workspace_abs | path join $dir) | path exists)
    }

    let missing_files = $required_files | where {|file|
        not (($workspace_abs | path join $file) | path exists)
    }

    let is_valid = ($missing_dirs | is-empty) and ($missing_files | is-empty)

    {
        valid: $is_valid
        workspace: $workspace_abs
        missing_directories: $missing_dirs
        missing_files: $missing_files
        recommendations: (if not $is_valid {
            ["Run 'workspace-init.nu <path>' to fix workspace structure"]
        } else {
            []
        })
    }
}
