#!/usr/bin/env nu

# Workspace Migration Tool
# Migrates existing workspaces to new KCL package and module loader structure

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

# Main migration command
def main [workspace_path: string] {
    print $"Migrating workspace: ($workspace_path)"

    # Validate workspace exists
    if not ($workspace_path | path exists) {
        error make { msg: $"Workspace not found: ($workspace_path)" }
    }

    # Analyze current workspace
    let analysis = analyze-workspace $workspace_path

    print $"📊 Workspace Analysis:"
    print $"  Type: ($analysis.type)"
    print $"  KCL files: ($analysis.kcl_files | length)"
    print $"  Has kcl.mod: ($analysis.has_kcl_mod)"
    print $"  Extension references: ($analysis.extension_refs | length)"

    # Perform migration steps
    let migration_result = migrate-workspace $workspace_path $analysis

    print $"✅ Migration completed"
    print $"📁 New structure created"
    print $"📄 Configuration files updated"
    print $"🔄 Import paths converted"

    if not ($migration_result.warnings | is-empty) {
        print ""
        print "⚠️  Warnings:"
        for $warning in $migration_result.warnings {
            print $"  - ($warning)"
        }
    }

    print ""
    print "Next steps:"
    print "  1. Review updated kcl.mod file"
    print "  2. Load required modules: module-loader load taskservs . [modules...]"
    print "  3. Test configuration: kcl run servers.k"
    print "  4. Deploy: provisioning server create --infra . --check"
}

# Analyze existing workspace structure
def analyze-workspace [workspace_path: string]: nothing -> record {
    let workspace_abs = ($workspace_path | path expand)

    # Find KCL files
    let kcl_files = try {
        glob ($workspace_abs | path join "**/*.k") | where { |path| $path | path exists }
    } catch { [] }

    # Check for kcl.mod
    let kcl_mod_path = ($workspace_abs | path join "kcl.mod")
    let has_kcl_mod = ($kcl_mod_path | path exists)

    # Find extension references in KCL files
    let extension_refs = ($kcl_files | each { |file|
        let content = try { open $file } catch { "" }
        # Look for relative imports pointing to extensions
        let imports = ($content | lines | where { |line| ($line | str contains "import") and ($line | str contains "../") })
        $imports | each { |import| { file: $file, import: $import } }
    } | flatten)

    # Detect workspace type
    let workspace_type = if ($extension_refs | where { |ref| $ref.import | str contains "taskservs" } | length) > 0 {
        "legacy-with-taskservs"
    } else if ($kcl_files | length) > 0 {
        "kcl-workspace"
    } else {
        "basic"
    }

    {
        path: $workspace_abs,
        type: $workspace_type,
        kcl_files: $kcl_files,
        has_kcl_mod: $has_kcl_mod,
        extension_refs: $extension_refs,
        needs_migration: ((not $has_kcl_mod) or (($extension_refs | length) > 0))
    }
}

# Perform workspace migration
def migrate-workspace [workspace_path: string, analysis: record]: nothing -> record {
    let workspace_abs = ($workspace_path | path expand)
    let warnings = []

    # Step 1: Create new directory structure
    print "🔧 Creating new directory structure..."
    mkdir ($workspace_abs | path join ".taskservs")
    mkdir ($workspace_abs | path join ".providers")
    mkdir ($workspace_abs | path join ".clusters")
    mkdir ($workspace_abs | path join ".manifest")

    # Ensure other standard directories exist
    mkdir ($workspace_abs | path join "data")
    mkdir ($workspace_abs | path join "tmp")
    mkdir ($workspace_abs | path join "resources")
    mkdir ($workspace_abs | path join "clusters")

    # Step 2: Create or update kcl.mod
    print "🔧 Creating/updating kcl.mod..."
    let kcl_mod_content = if $analysis.has_kcl_mod {
        # Update existing kcl.mod
        let existing = (open ($workspace_abs | path join "kcl.mod"))
        update-kcl-mod $existing
    } else {
        # Create new kcl.mod
        create-new-kcl-mod ($workspace_path | path basename)
    }
    $kcl_mod_content | save -f ($workspace_abs | path join "kcl.mod")

    # Step 3: Convert import paths in KCL files
    print "🔧 Converting import paths..."
    let conversion_results = ($analysis.kcl_files | each { |file|
        convert-imports-in-file $file
    })

    # Step 4: Create empty manifest files
    print "🔧 Creating manifest files..."
    let empty_manifest = {
        last_updated: (date now | format date "%Y-%m-%d %H:%M:%S"),
        workspace: $workspace_abs
    }

    ($empty_manifest | merge { loaded_taskservs: [] }) | to yaml | save -f ($workspace_abs | path join ".manifest" | path join "taskservs.yaml")
    ($empty_manifest | merge { loaded_providers: [] }) | to yaml | save -f ($workspace_abs | path join ".manifest" | path join "providers.yaml")
    ($empty_manifest | merge { loaded_clusters: [] }) | to yaml | save -f ($workspace_abs | path join ".manifest" | path join "clusters.yaml")

    # Step 5: Create .gitignore if it doesn't exist
    let gitignore_path = ($workspace_abs | path join ".gitignore")
    if not ($gitignore_path | path exists) {
        print "🔧 Creating .gitignore..."
        let gitignore_content = "# Workspace runtime data
.manifest/
data/
tmp/
*.log

# Module directories (managed by module-loader)
.taskservs/
.providers/
.clusters/

# Generated files
taskservs.k
providers.k
clusters.k

# Secrets and sensitive data
*.age
*.enc
*.key
"
        $gitignore_content | save $gitignore_path
    }

    # Step 6: Create migration summary
    let migration_info = {
        migrated_at: (date now | format date "%Y-%m-%d %H:%M:%S"),
        original_type: $analysis.type,
        files_converted: ($conversion_results | length),
        extension_refs_converted: ($analysis.extension_refs | length)
    }

    $migration_info | to yaml | save ($workspace_abs | path join ".migration-info.yaml")

    {
        success: true,
        workspace: $workspace_abs,
        files_converted: ($conversion_results | length),
        warnings: $warnings
    }
}

# Update existing kcl.mod to add provisioning dependency
def update-kcl-mod [existing_content: string]: nothing -> string {
    let lines = ($existing_content | lines)

    # Check if provisioning dependency already exists
    let has_provisioning_dep = ($lines | any { |line| $line | str contains "provisioning" })

    if $has_provisioning_dep {
        return $existing_content
    }

    # Find [dependencies] section or add it
    let deps_line_idx = ($lines | enumerate | where { |item| $item.item | str contains "[dependencies]" } | get index | first)

    if ($deps_line_idx | is-empty) {
        # Add dependencies section
        $existing_content + "\n\n[dependencies]\nprovisioning = { path = \"~/.kcl/packages/provisioning\", version = \"0.0.1\" }\n"
    } else {
        # Insert after dependencies line
        let before = ($lines | first ($deps_line_idx + 1))
        let after = ($lines | skip ($deps_line_idx + 1))
        ($before | append ["provisioning = { path = \"~/.kcl/packages/provisioning\", version = \"0.0.1\" }"] | append $after | str join "\n")
    }
}

# Create new kcl.mod file
def create-new-kcl-mod [workspace_name: string]: nothing -> string {
    $"[package]
name = \"($workspace_name)\"
edition = \"v0.11.3\"
version = \"0.0.1\"

[dependencies]
provisioning = { path = \"~/.kcl/packages/provisioning\", version = \"0.0.1\" }
"
}

# Convert import paths in a KCL file
def convert-imports-in-file [file_path: string]: nothing -> record {
    let content = try { open $file_path } catch { return { file: $file_path, status: "error", message: "Could not read file" } }

    # Define import conversion patterns
    let conversions = [
        # Convert relative imports to package imports
        { pattern: "import ../../../kcl/", replacement: "import provisioning." }
        { pattern: "import ../../kcl/", replacement: "import provisioning." }
        { pattern: "import ../kcl/", replacement: "import provisioning." }

        # Convert extension imports (these will need to be loaded via module-loader)
        { pattern: "import ../../../extensions/taskservs/", replacement: "# import .taskservs." }
        { pattern: "import ../../extensions/taskservs/", replacement: "# import .taskservs." }
        { pattern: "import ../extensions/taskservs/", replacement: "# import .taskservs." }

        { pattern: "import ../../../extensions/providers/", replacement: "# import .providers." }
        { pattern: "import ../../extensions/providers/", replacement: "# import .providers." }
        { pattern: "import ../extensions/providers/", replacement: "# import .providers." }

        { pattern: "import ../../../extensions/clusters/", replacement: "# import .clusters." }
        { pattern: "import ../../extensions/clusters/", replacement: "# import .clusters." }
        { pattern: "import ../extensions/clusters/", replacement: "# import .clusters." }
    ]

    # Apply conversions
    let updated_content = ($conversions | reduce -f $content { |acc, conv|
        $acc | str replace -a $conv.pattern $conv.replacement
    })

    # Check if any changes were made
    if $content != $updated_content {
        # Backup original file
        let backup_path = ($file_path + ".bak")
        $content | save $backup_path

        # Save updated content
        $updated_content | save -f $file_path

        {
            file: $file_path,
            status: "converted",
            backup: $backup_path,
            changes: true
        }
    } else {
        {
            file: $file_path,
            status: "no-changes",
            changes: false
        }
    }
}

# Dry run migration (analyze what would be changed)
export def "main dry-run" [workspace_path: string]: nothing -> record {
    print $"Analyzing workspace for migration: ($workspace_path)"

    let analysis = analyze-workspace $workspace_path

    print $"📊 Migration Analysis Report:"
    print $"  Workspace: ($analysis.path)"
    print $"  Type: ($analysis.type)"
    print $"  Needs migration: ($analysis.needs_migration)"
    print ""
    print $"  KCL files found: ($analysis.kcl_files | length)"
    for $file in $analysis.kcl_files {
        print $"    - ($file | str replace ($analysis.path + '/') '')"
    }
    print ""
    print $"  Extension references: ($analysis.extension_refs | length)"
    for $ref in $analysis.extension_refs {
        let file_rel = ($ref.file | str replace ($analysis.path + '/') '')
        print $"    - ($file_rel): ($ref.import | str trim)"
    }

    if $analysis.needs_migration {
        print ""
        print "🔧 Migration steps that would be performed:"
        print "  1. Create .taskservs/, .providers/, .clusters/, .manifest/ directories"
        print "  2. Create/update kcl.mod with provisioning dependency"
        print "  3. Convert import paths from relative to package-based"
        print "  4. Comment out extension imports (load via module-loader)"
        print "  5. Create manifest files for module tracking"
        print "  6. Create .gitignore if missing"
    } else {
        print ""
        print "✅ Workspace appears to already be migrated or needs no migration"
    }

    $analysis
}

# Rollback migration (restore from backups)
export def "main rollback" [workspace_path: string]: nothing -> nothing {
    print $"Rolling back migration for: ($workspace_path)"

    let workspace_abs = ($workspace_path | path expand)

    # Find backup files
    let backup_files = try {
        glob ($workspace_abs | path join "**/*.bak")
    } catch { [] }

    if ($backup_files | is-empty) {
        print "⚠️  No backup files found. Cannot rollback."
        return
    }

    print $"Found ($backup_files | length) backup files"

    # Restore each backup
    for $backup in $backup_files {
        let original = ($backup | str replace ".bak" "")
        print $"Restoring: ($original | str replace ($workspace_abs + '/') '')"

        # Copy backup back to original
        cp $backup $original

        # Remove backup
        rm $backup
    }

    # Remove migration artifacts
    let migration_artifacts = [
        ".taskservs"
        ".providers"
        ".clusters"
        ".manifest"
        ".migration-info.yaml"
    ]

    for $artifact in $migration_artifacts {
        let artifact_path = ($workspace_abs | path join $artifact)
        if ($artifact_path | path exists) {
            rm -rf $artifact_path
        }
    }

    print "✅ Migration rolled back successfully"
    print "   Original files restored from backups"
    print "   Migration artifacts removed"
}

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

    let has_new_structure = [".taskservs", ".providers", ".clusters", ".manifest"] | all { |dir|
        ($workspace_abs | path join $dir) | path exists
    }

    let migration_info_path = ($workspace_abs | path join ".migration-info.yaml")
    let migration_info = if ($migration_info_path | path exists) {
        open $migration_info_path
    } else {
        null
    }

    let backup_files = try {
        glob ($workspace_abs | path join "**/*.bak") | length
    } catch { 0 }

    {
        workspace: $workspace_abs,
        has_new_structure: $has_new_structure,
        migration_info: $migration_info,
        backup_files: $backup_files,
        is_migrated: ($has_new_structure and ($migration_info != null))
    }
}
