#!/usr/bin/env nu

# Taskserv Loader System
# Loads selected taskservs into workspace or infrastructure (Layer 2 or Layer 3)

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

# Load taskservs into workspace or infrastructure
export def load-taskservs [
    target_path: string,
    taskservs: 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 taskservs 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 taskservs exist in system
    let validation = (validate-taskservs $taskservs)
    if not $validation.valid {
        error make { msg: $"Missing taskservs: ($validation.missing)" }
    }

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

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

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

    # Create/update manifest
    update-taskservs-manifest $load_path $taskservs $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 (($taskservs | length)) taskservs at ($layer_info.layer) layer"
    }
}

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

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

        # Copy Nickel files and directories
        mkdir $target_dir
        let source_items = (ls $taskserv_info.schema_path | get name)
        for $item in $source_items {
            cp -r $item $target_dir
        }

        print $"✅ Loaded taskserv: ($name)"
        {
            name: $name
            status: "success"
            path: $target_dir
            version: $taskserv_info.version
        }
    } | complete)

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

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

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

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

($imports)

# Export all loaded taskserv schemas
taskservs = {
($exports)
}

taskservs"

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

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

import .taskservs.($name) as ($name)

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

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

    let taskserv_entries = ($taskservs | each { |name|
        let info = (get-taskserv-info $name)
        {
            name: $name
            version: $info.version
            layer: $layer
            loaded_at: (date now | format date '%Y-%m-%d %H:%M:%S')
            source_path: $info.schema_path
        }
    })

    let manifest = {
        loaded_taskservs: $taskserv_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 taskserv from workspace
export def unload-taskserv [workspace: string, name: string] {
    let target_dir = ($workspace | path join ".taskservs" $name)

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

    rm -rf $target_dir

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

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

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

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

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

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

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