# Workspace Enforcement Module
# Enforces workspace requirements for all provisioning operations

use std log
# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/user/config.nu [get-active-workspace get-active-workspace-details]
use lib_provisioning/workspace/version.nu [check-workspace-compatibility validate-workspace-structure]

# Commands that are allowed without an active workspace
export def get-workspace-exempt-commands [] {
    [
        "help"
        "version"
        "workspace"
        "ws"
        "guide"
        "guides"
        "sc"
        "shortcuts"
        "howto"
        "nu"
        "nuinfo"
        "cache"
        "status"
        "health"
        "diagnostics"  # ✨ Diagnostics commands (workspace-agnostic)
        "next"
        "phase"
        "setup"        # ✨ System setup commands (workspace-agnostic)
        "st"           # Alias for setup
        "config"       # Alias for setup
        "platform"     # ✨ Platform services (workspace-agnostic)
        "plat"         # Alias for platform
        "providers"    # ✨ FIXED: provider list doesn't need workspace
        "plugin"
        "plugins"
        "taskserv"     # ✨ FIXED: taskserv list doesn't need workspace (list is read-only)
        "task"
        "server"       # ✨ FIXED: server list is read-only
        "cluster"      # ✨ FIXED: cluster list is read-only
        "infra"        # ✨ FIXED: infra list is read-only
        "-v"
        "--version"
        "-V"
        "--info"
        "-I"
        "--about"
        "-a"
        "--helpinfo"
        "-h"
    ]
}

# Check if command requires workspace
export def command-requires-workspace [
    command: string
] {
    let exempt_commands = (get-workspace-exempt-commands)

    # Check if command is in exempt list
    not ($exempt_commands | any { |cmd| $command == $cmd or $command starts-with $cmd })
}

# Enforce workspace requirement
export def enforce-workspace-requirement [
    command: string
    args: list<string>
] {
    # Check if command requires workspace
    if not (command-requires-workspace $command) {
        return {
            required: false
            allowed: true
            reason: "command_exempt"
        }
    }

    # Get active workspace
    let active_workspace = (get-active-workspace)

    if ($active_workspace == null or ($active_workspace | is-empty)) {
        return {
            required: true
            allowed: false
            reason: "no_active_workspace"
            message: "No active workspace. Please activate or create a workspace first."
        }
    }

    # Get workspace details
    let workspace_details = (get-active-workspace-details)

    if ($workspace_details == null or ($workspace_details | is-empty)) {
        return {
            required: true
            allowed: false
            reason: "workspace_not_found"
            message: $"Active workspace '($active_workspace)' not found in registry"
        }
    }

    let workspace_path = $workspace_details.path

    # Validate workspace exists on filesystem
    if not ($workspace_path | path exists) {
        return {
            required: true
            allowed: false
            reason: "workspace_path_missing"
            message: $"Workspace directory not found: ($workspace_path)"
            workspace_name: $active_workspace
        }
    }

    # Validate workspace structure
    let structure_validation = (validate-workspace-structure $workspace_path)

    if not $structure_validation.valid {
        let error_issues = ($structure_validation.issues | where severity == "error")
        return {
            required: true
            allowed: false
            reason: "invalid_workspace_structure"
            message: "Workspace structure is invalid"
            workspace_name: $active_workspace
            workspace_path: $workspace_path
            issues: $error_issues
        }
    }

    # Check workspace version compatibility
    let compatibility = (check-workspace-compatibility $workspace_path)

    if not $compatibility.compatible {
        return {
            required: true
            allowed: false
            reason: "version_incompatible"
            message: $compatibility.message
            workspace_name: $active_workspace
            workspace_path: $workspace_path
            compatibility: $compatibility
        }
    }

    # Workspace is valid and compatible
    return {
        required: true
        allowed: true
        reason: "workspace_valid"
        workspace_name: $active_workspace
        workspace_path: $workspace_path
        compatibility: $compatibility
    }
}

# Display workspace enforcement error
export def display-enforcement-error [
    enforcement_result: record
] {
    print ""
    print $"(ansi red_bold)✗ Workspace Required(ansi reset)"
    print ""

    match $enforcement_result.reason {
        "no_active_workspace" => {
            print $"(ansi yellow)No active workspace is configured.(ansi reset)"
            print ""
            print $"(ansi cyan)To get started:(ansi reset)"
            print ""
            print "  1. Create a new workspace:"
            print $"     (ansi green)provisioning workspace init <name>(ansi reset)"
            print ""
            print "  2. Or activate an existing workspace:"
            print $"     (ansi green)provisioning workspace activate <name>(ansi reset)"
            print ""
            print "  3. List available workspaces:"
            print $"     (ansi green)provisioning workspace list(ansi reset)"
            print ""
        }

        "workspace_not_found" => {
            print $"(ansi yellow)Active workspace not found in registry.(ansi reset)"
            print ""
            print $"(ansi cyan)To fix this:(ansi reset)"
            print ""
            print "  1. List available workspaces:"
            print $"     (ansi green)provisioning workspace list(ansi reset)"
            print ""
            print "  2. Activate a different workspace:"
            print $"     (ansi green)provisioning workspace activate <name>(ansi reset)"
            print ""
        }

        "workspace_path_missing" => {
            print $"(ansi yellow)Workspace directory not found:(ansi reset)"
            print $"  ($enforcement_result.workspace_name)"
            print ""
            print $"(ansi cyan)The workspace may have been moved or deleted.(ansi reset)"
            print ""
            print "  1. Remove the workspace from registry:"
            print $"     (ansi green)provisioning workspace remove ($enforcement_result.workspace_name)(ansi reset)"
            print ""
            print "  2. Create a new workspace:"
            print $"     (ansi green)provisioning workspace init <name>(ansi reset)"
            print ""
        }

        "invalid_workspace_structure" => {
            print $"(ansi yellow)Workspace has invalid structure:(ansi reset)"
            print $"  Workspace: ($enforcement_result.workspace_name)"
            print $"  Path: ($enforcement_result.workspace_path)"
            print ""
            print $"(ansi red)Issues found:(ansi reset)"
            for issue in $enforcement_result.issues {
                print $"  • ($issue.message)"
            }
            print ""
            print $"(ansi cyan)To fix this:(ansi reset)"
            print ""
            print "  1. Run workspace migration:"
            print $"     (ansi green)provisioning workspace migrate ($enforcement_result.workspace_name)(ansi reset)"
            print ""
            print "  2. Or create a new workspace:"
            print $"     (ansi green)provisioning workspace init <name>(ansi reset)"
            print ""
        }

        "version_incompatible" => {
            print $"(ansi yellow)Workspace version is incompatible:(ansi reset)"
            print $"  Workspace: ($enforcement_result.workspace_name)"
            print $"  Path: ($enforcement_result.workspace_path)"
            print ""
            print $"(ansi red)($enforcement_result.message)(ansi reset)"
            print ""

            let compat = $enforcement_result.compatibility

            if ($compat.reason == "no_metadata") {
                print $"(ansi cyan)This workspace needs migration:(ansi reset)"
                print ""
                print "  Run workspace migration:"
                print $"     (ansi green)provisioning workspace migrate ($enforcement_result.workspace_name)(ansi reset)"
                print ""
            } else if ($compat.reason == "workspace_too_new") {
                print $"(ansi cyan)Workspace is newer than the system:(ansi reset)"
                print $"  Workspace version: ($compat.workspace_version)"
                print $"  System version: ($compat.current_system)"
                print ""
                print "  Upgrade the provisioning system to use this workspace."
                print ""
            } else if ($compat.reason == "migration_available") {
                print $"(ansi cyan)Workspace can be migrated:(ansi reset)"
                print $"  From: ($compat.workspace_version)"
                print $"  To: ($compat.current_system)"
                print ""
                print "  Run workspace migration:"
                print $"     (ansi green)provisioning workspace migrate ($enforcement_result.workspace_name)(ansi reset)"
                print ""
            } else if ($compat.reason == "version_too_old") {
                print $"(ansi cyan)System version is too old:(ansi reset)"
                print $"  Required: ($compat.min_required)"
                print $"  Current: ($compat.current_system)"
                print ""
                print "  Upgrade the provisioning system to continue."
                print ""
            }
        }

        _ => {
            print $"(ansi yellow)($enforcement_result.message)(ansi reset)"
            print ""
        }
    }
}

# Check and enforce workspace requirement (main entry point)
export def check-and-enforce [
    command: string
    args: list<string>
] {
    let enforcement = (enforce-workspace-requirement $command $args)

    if not $enforcement.allowed {
        display-enforcement-error $enforcement
        return false
    }

    # If workspace is required and valid, optionally show compatibility warnings
    if $enforcement.required and $enforcement.compatibility.requires_migration? {
        if ($enforcement.compatibility.migration_optional? | default false) {
            print $"(ansi yellow)ℹ Migration available: Workspace can be updated from ($enforcement.compatibility.workspace_version) to ($enforcement.compatibility.current_system)(ansi reset)"
            print $"  Run: (ansi green)provisioning workspace migrate ($enforcement.workspace_name)(ansi reset)"
            print ""
        }
    }

    return true
}

# Get current workspace info (for enforcement checks)
export def get-current-workspace-info [] {
    let active_workspace = (get-active-workspace)

    if ($active_workspace == null or ($active_workspace | is-empty)) {
        return {
            active: false
            name: null
            path: null
        }
    }

    let workspace_details = (get-active-workspace-details)

    if ($workspace_details == null or ($workspace_details | is-empty)) {
        return {
            active: false
            name: $active_workspace
            path: null
        }
    }

    return {
        active: true
        name: $workspace_details.name
        path: $workspace_details.path
        last_used: $workspace_details.last_used
    }
}

# Pre-flight check for operations
export def preflight-check [
    operation: string
] {
    let workspace_info = (get-current-workspace-info)

    if not $workspace_info.active {
        return {
            passed: false
            reason: "no_workspace"
            message: "No active workspace"
        }
    }

    # Check workspace structure
    let structure = (validate-workspace-structure $workspace_info.path)

    if not $structure.valid {
        return {
            passed: false
            reason: "invalid_structure"
            message: "Workspace structure is invalid"
            issues: $structure.issues
        }
    }

    # Check version compatibility
    let compatibility = (check-workspace-compatibility $workspace_info.path)

    if not $compatibility.compatible {
        return {
            passed: false
            reason: "incompatible_version"
            message: $compatibility.message
            compatibility: $compatibility
        }
    }

    return {
        passed: true
        workspace: $workspace_info
        compatibility: $compatibility
    }
}
