# Configuration Migration Tool
# Helps migrate from environment variable based configuration to the new config system

use std log

# Mapping of old environment variables to new config paths
export def get-env-mapping [] {
    [
        { env_var: "PROVISIONING", config_path: "paths.base", description: "Base provisioning path" }
        { env_var: "PROVISIONING_WORKSPACE_PATH", config_path: "paths.workspace", description: "Infrastructure workspace path" }
        { env_var: "PROVISIONING_PROVIDERS_PATH", config_path: "paths.providers", description: "Providers path" }
        { env_var: "PROVISIONING_TASKSERVS_PATH", config_path: "paths.taskservs", description: "Task services path" }
        { env_var: "PROVISIONING_CLUSTERS_PATH", config_path: "paths.clusters", description: "Clusters path" }
        { env_var: "PROVISIONING_RESOURCES", config_path: "paths.resources", description: "Resources path" }
        { env_var: "PROVISIONING_TEMPLATES_PATH", config_path: "paths.templates", description: "Templates path" }
        { env_var: "PROVISIONING_TOOLS_PATH", config_path: "paths.tools", description: "Tools path" }
        { env_var: "PROVISIONING_CORE", config_path: "paths.core", description: "Core path" }

        { env_var: "PROVISIONING_DEBUG", config_path: "debug.enabled", description: "Debug mode" }
        { env_var: "PROVISIONING_METADATA", config_path: "debug.metadata", description: "Metadata debug" }
        { env_var: "PROVISIONING_DEBUG_CHECK", config_path: "debug.check", description: "Debug check mode" }
        { env_var: "PROVISIONING_DEBUG_REMOTE", config_path: "debug.remote", description: "Remote debug mode" }
        { env_var: "PROVISIONING_LOG_LEVEL", config_path: "debug.log_level", description: "Log level" }
        { env_var: "PROVISIONING_NO_TERMINAL", config_path: "debug.no_terminal", description: "No terminal mode" }

        { env_var: "PROVISIONING_FILEVIEWER", config_path: "output.file_viewer", description: "File viewer command" }
        { env_var: "PROVISIONING_WK_FORMAT", config_path: "output.format", description: "Working format" }

        { env_var: "PROVISIONING_USE_SOPS", config_path: "sops.use_sops", description: "SOPS encryption type" }
        { env_var: "PROVISIONING_KAGE", config_path: "sops.key_search_paths.0", description: "Primary SOPS key path" }
        { env_var: "PROVISIONING_SOPS", config_path: "sops.config_path", description: "SOPS config path" }

        { env_var: "PROVISIONING_DEFAULT_SETTINGS", config_path: "paths.files.settings", description: "Default settings file" }
        { env_var: "PROVISIONING_KEYS_PATH", config_path: "paths.files.keys", description: "Keys file path" }
        { env_var: "PROVISIONING_REQ_VERSIONS", config_path: "paths.files.requirements", description: "Requirements file" }
        { env_var: "PROVISIONING_NOTIFY_ICON", config_path: "paths.files.notify_icon", description: "Notification icon" }

        { env_var: "PROVISIONING_RUN_TASKSERVS_PATH", config_path: "taskservs.run_path", description: "Task services run path" }
        { env_var: "PROVISIONING_RUN_CLUSTERS_PATH", config_path: "clusters.run_path", description: "Clusters run path" }
        { env_var: "PROVISIONING_GENERATE_DIRPATH", config_path: "generation.dir_path", description: "Generation directory" }
        { env_var: "PROVISIONING_GENERATE_DEFSFILE", config_path: "generation.defs_file", description: "Generation definitions file" }
    ]
}

# Analyze current environment variables and suggest migration
export def analyze-current-env [] {
    let mapping = (get-env-mapping)
    mut analysis = []

    for entry in $mapping {
        let env_var_name = $entry.env_var
        let env_value = if ($env_var_name in ($env | columns)) { $env | get $env_var_name } else { null }
        if ($env_value | is-not-empty) {
            $analysis = ($analysis | append {
                env_var: $entry.env_var
                current_value: $env_value
                config_path: $entry.config_path
                description: $entry.description
                action: "migrate"
            })
        } else {
            $analysis = ($analysis | append {
                env_var: $entry.env_var
                current_value: "not set"
                config_path: $entry.config_path
                description: $entry.description
                action: "default"
            })
        }
    }

    $analysis
}

# Generate user configuration based on current environment variables
export def generate-user-config [
    --output: string = ""           # Output file (default: ~/.config/provisioning/config.toml)
    --dry-run = false               # Show what would be generated without writing
] {
    let analysis = (analyze-current-env)
    let active_vars = ($analysis | where action == "migrate")

    if ($active_vars | is-empty) {
        print "No environment variables found to migrate"
        return
    }

    # Build configuration structure
    mut config = {
        core: {
            name: "provisioning"
        }
        paths: {}
        debug: {}
        output: {}
        sops: {
            key_search_paths: []
        }
    }

    # Convert environment variables to config structure
    for var in $active_vars {
        $config = (set-config-value $config $var.config_path $var.current_value)
    }

    # Convert to TOML
    let config_toml = ($config | to toml)

    let output_path = if ($output | is-empty) {
        ($env.HOME | path join ".config" | path join "provisioning" | path join "config.toml")
    } else {
        $output
    }

    if $dry_run {
        print "Generated configuration (dry run):"
        print "=====================================\n"
        print $config_toml
        print $"\nWould be written to: ($output_path)"
    } else {
        # Ensure directory exists
        let config_dir = ($output_path | path dirname)
        if not ($config_dir | path exists) {
            mkdir $config_dir
            print $"Created directory: ($config_dir)"
        }

        # Write configuration
        $config_toml | save $output_path
        print $"Generated user configuration: ($output_path)"
        print "Review and edit this file as needed"
    }
}

# Set a nested configuration value using dot notation
def set-config-value [
    config: record
    path: string
    value: any
] {
    let path_parts = ($path | split row ".")

    if ($path_parts | length) == 1 {
        # Simple top-level assignment
        return ($config | upsert ($path_parts | first) $value)
    }

    # Handle nested paths
    let first_part = ($path_parts | first)
    let remaining_path = ($path_parts | skip 1 | str join ".")

    let existing_section = if ($first_part in ($config | columns)) { $config | get $first_part } else { {} }
    let updated_section = (set-config-value $existing_section $remaining_path $value)

    $config | upsert $first_part $updated_section
}

# Check for potential issues in the migration
export def check-migration-issues [] {
    let analysis = (analyze-current-env)
    mut issues = []

    # Check for conflicting paths
    let base_path = if ("PROVISIONING" in ($env | columns)) { $env.PROVISIONING } else { null }
    if ($base_path | is-not-empty) and not ($base_path | path exists) {
        $issues = ($issues | append {
            type: "missing_path"
            item: "PROVISIONING"
            value: $base_path
            issue: "Base path does not exist"
            severity: "error"
        })
    }

    # Check for SOPS configuration
    let sops_key = if ("PROVISIONING_KAGE" in ($env | columns)) { $env.PROVISIONING_KAGE } else { null }
    if ($sops_key | is-not-empty) and not ($sops_key | path exists) {
        $issues = ($issues | append {
            type: "missing_file"
            item: "PROVISIONING_KAGE"
            value: $sops_key
            issue: "SOPS key file does not exist"
            severity: "warning"
        })
    }

    # Check for deprecated variables that should be removed
    let deprecated_vars = [
        "PROVISIONING_ARGS"
        "PROVISIONING_MODULE"
        "PROVISIONING_NAME"
        "PROVISIONING_OUT"
        "PROVISIONING_LAST_ERROR"
    ]

    for var in $deprecated_vars {
        let value = if ($var in ($env | columns)) { $env | get $var } else { null }
        if ($value | is-not-empty) {
            $issues = ($issues | append {
                type: "deprecated"
                item: $var
                value: $value
                issue: "This variable is deprecated and should be removed"
                severity: "info"
            })
        }
    }

    $issues
}

# Show migration status and recommendations
export def show-migration-status [] {
    print "🔄 Environment Variable Migration Analysis"
    print "==========================================\n"

    let analysis = (analyze-current-env)
    let to_migrate = ($analysis | where action == "migrate")
    let using_defaults = ($analysis | where action == "default")

    print $"📊 Summary:"
    print $"   • Variables to migrate: ($to_migrate | length)"
    print $"   • Using system defaults: ($using_defaults | length)"
    print ""

    if ($to_migrate | length) > 0 {
        print "🔧 Variables that will be migrated:"
        $to_migrate | select env_var current_value config_path | table --index false
        print ""
    }

    let issues = (check-migration-issues)
    if ($issues | length) > 0 {
        print "⚠️  Potential issues found:"
        $issues | table --index false
        print ""
    }

    print "💡 Next steps:"
    print "   1. Run 'migration generate-user-config --dry-run' to preview"
    print "   2. Run 'migration generate-user-config' to create config file"
    print "   3. Test the new configuration system"
    print "   4. Remove old environment variables from your shell profile"
}

# Create a backup of current environment variables
export def backup-current-env [
    output: string = "provisioning-env-backup.nu"
] {
    let mapping = (get-env-mapping)
    mut backup_content = "# Backup of provisioning environment variables\n"
    $backup_content = ($backup_content + "# Generated on " + (date now | format date "%Y-%m-%d %H:%M:%S") + "\n\n")

    for entry in $mapping {
        let env_var_name = $entry.env_var
        let env_value = if ($env_var_name in ($env | columns)) { $env | get $env_var_name } else { null }
        if ($env_value | is-not-empty) {
            $backup_content = ($backup_content + $"$env.($entry.env_var) = \"($env_value)\"\n")
        }
    }

    $backup_content | save $output
    print $"Environment variables backed up to: ($output)"
}
