# Mode Management Commands
# Execution mode switching and configuration for provisioning system
#
# Modes:
#   - solo: Single developer local development
#   - multi-user: Team collaboration with shared services
#   - cicd: CI/CD pipeline execution
#   - enterprise: Production enterprise deployment

use ../utils/logging.nu *

# Get current active mode
export def "mode current" [] -> record {
    let mode_file = get-mode-config-path

    if not ($mode_file | path exists) {
        return {
            mode: "solo"
            configured: false
            config_file: null
            message: "No mode configured, using default 'solo' mode"
        }
    }

    let config = open $mode_file

    {
        mode: $config.mode
        configured: true
        config_file: $mode_file
        description: $config.description?
    }
}

# List all available modes
export def "mode list" [] -> table {
    let modes_dir = get-modes-dir

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

    ls $modes_dir
    | where name =~ ".yaml$"
    | each {|it|
        let config = open $it.name
        let is_current = (is-current-mode $config.mode)

        {
            mode: $config.mode
            description: $config.description
            current: $is_current
            config_file: $it.name
        }
    }
    | sort-by mode
}

# Show mode information
export def "mode show" [
    mode_name?: string  # Mode to show (defaults to current)
] -> record {
    let target_mode = if ($mode_name == null) {
        (mode current).mode
    } else {
        $mode_name
    }

    let config_file = get-mode-file $target_mode

    if not ($config_file | path exists) {
        error make {
            msg: $"Mode '($target_mode)' not found"
            label: {
                text: "Available modes: solo, multi-user, cicd, enterprise"
                span: (metadata $mode_name).span
            }
        }
    }

    open $config_file
}

# Switch to a different mode
export def "mode switch" [
    mode_name: string   # Mode to switch to (solo, multi-user, cicd, enterprise)
    --validate          # Validate mode configuration before switching
    --dry-run           # Show what would change without applying
] -> nothing {
    # Validate mode exists
    let config_file = get-mode-file $mode_name

    if not ($config_file | path exists) {
        error make {
            msg: $"Mode '($mode_name)' configuration not found"
            label: {
                text: $"Expected: ($config_file)"
                span: (metadata $mode_name).span
            }
        }
    }

    # Load and validate configuration
    let config = open $config_file

    if $validate {
        log-info $"Validating mode configuration: ($mode_name)"
        mode validate $mode_name
    }

    # Get current mode
    let current = (mode current).mode

    if $dry_run {
        print $"Would switch from '($current)' to '($mode_name)'"
        print $"\nConfiguration changes:"
        print $config
        return
    }

    # Confirm switch (unless in non-interactive mode)
    if (is-interactive) and ($current != $mode_name) {
        let confirm = (input $"Switch from '($current)' to '($mode_name)' mode? \(y/N\) ")
        if ($confirm | str downcase) != "y" {
            log-info "Mode switch cancelled"
            return
        }
    }

    # Copy mode config to active config
    let active_config = get-mode-config-path

    # Backup current config if exists
    if ($active_config | path exists) {
        let backup = $"($active_config).backup"
        cp $active_config $backup
        log-debug $"Backed up current config to ($backup)"
    }

    # Copy new mode config
    cp $config_file $active_config

    log-info $"Switched to '($mode_name)' mode"

    # Show next steps based on mode
    show-mode-next-steps $mode_name
}

# Validate mode configuration
export def "mode validate" [
    mode_name?: string  # Mode to validate (defaults to current)
] -> record {
    let target_mode = if ($mode_name == null) {
        (mode current).mode
    } else {
        $mode_name
    }

    let config_file = get-mode-file $target_mode

    if not ($config_file | path exists) {
        error make {
            msg: $"Mode configuration not found: ($config_file)"
        }
    }

    log-info $"Validating mode: ($target_mode)"

    let config = open $config_file
    mut validation_results = []

    # Validate required fields
    let required_fields = ["mode", "description", "authentication", "services", "extensions", "workspaces", "security"]

    for field in $required_fields {
        if ($field in $config) {
            $validation_results = ($validation_results | append {
                check: $"Required field: ($field)"
                status: "pass"
            })
        } else {
            $validation_results = ($validation_results | append {
                check: $"Required field: ($field)"
                status: "fail"
                message: $"Missing required field: ($field)"
            })
        }
    }

    # Validate service configurations
    let service_checks = validate-services $config.services
    $validation_results = ($validation_results | append $service_checks)

    # Validate authentication
    let auth_checks = validate-authentication $config.authentication
    $validation_results = ($validation_results | append $auth_checks)

    # Validate extensions
    let ext_checks = validate-extensions $config.extensions
    $validation_results = ($validation_results | append $ext_checks)

    # Count results
    let total = ($validation_results | length)
    let passed = ($validation_results | where status == "pass" | length)
    let failed = ($validation_results | where status == "fail" | length)

    # Display results
    print $"\nValidation Results for '($target_mode)' mode:"
    print $"  Total checks: ($total)"
    print $"  Passed: ($passed)"
    print $"  Failed: ($failed)"

    if $failed > 0 {
        print $"\nFailed checks:"
        $validation_results
        | where status == "fail"
        | each {|it| print $"  ✗ ($it.check): ($it.message)"}
    }

    {
        mode: $target_mode
        total_checks: $total
        passed: $passed
        failed: $failed
        success: ($failed == 0)
        checks: $validation_results
    }
}

# Initialize mode system
export def "mode init" [] -> nothing {
    log-info "Initializing mode system"

    let modes_dir = get-modes-dir

    # Create modes directory if not exists
    if not ($modes_dir | path exists) {
        mkdir $modes_dir
        log-debug $"Created modes directory: ($modes_dir)"
    }

    # Check if mode configs exist
    let mode_files = ["solo.yaml", "multi-user.yaml", "cicd.yaml", "enterprise.yaml"]

    for mode_file in $mode_files {
        let full_path = ($modes_dir | path join $mode_file)
        if not ($full_path | path exists) {
            log-warning $"Mode configuration missing: ($mode_file)"
        }
    }

    # Initialize to solo mode if no active config
    let active_config = get-mode-config-path
    if not ($active_config | path exists) {
        log-info "No active mode configuration, initializing to 'solo' mode"
        mode switch solo --no-confirm
    }

    log-info "Mode system initialized"
}

# OCI registry management
export def "mode oci-registry" [
    action: string      # Action: start, stop, status, logs
] -> nothing {
    let current_mode = (mode current)
    let config = mode show

    if ($config.services.oci-registry.deployment == "disabled") {
        log-error "OCI registry is disabled in current mode"
        return
    }

    if ($config.services.oci-registry.deployment != "local") {
        log-error "OCI registry management only available for local deployment"
        log-info $"Current deployment: ($config.services.oci-registry.deployment)"
        return
    }

    match $action {
        "start" => { start-oci-registry $config }
        "stop" => { stop-oci-registry $config }
        "status" => { oci-registry-status $config }
        "logs" => { oci-registry-logs $config }
        _ => {
            error make {
                msg: $"Unknown action: ($action)"
                label: {
                    text: "Valid actions: start, stop, status, logs"
                    span: (metadata $action).span
                }
            }
        }
    }
}

# Compare modes
export def "mode compare" [
    mode1: string       # First mode to compare
    mode2: string       # Second mode to compare
] -> record {
    let config1 = mode show $mode1
    let config2 = mode show $mode2

    print $"\nComparing '($mode1)' and '($mode2)' modes:\n"

    # Compare key aspects
    print "Authentication:"
    print $"  ($mode1): ($config1.authentication.type)"
    print $"  ($mode2): ($config2.authentication.type)"

    print "\nService Deployments:"
    print $"  Orchestrator:"
    print $"    ($mode1): ($config1.services.orchestrator.deployment)"
    print $"    ($mode2): ($config2.services.orchestrator.deployment)"

    print $"  OCI Registry:"
    print $"    ($mode1): ($config1.services.oci-registry.deployment) \(($config1.services.oci-registry.type))"
    print $"    ($mode2): ($config2.services.oci-registry.deployment) \(($config2.services.oci-registry.type))"

    print "\nExtension Source:"
    print $"  ($mode1): ($config1.extensions.source)"
    print $"  ($mode2): ($config2.extensions.source)"

    print "\nWorkspace Locking:"
    print $"  ($mode1): ($config1.workspaces.locking)"
    print $"  ($mode2): ($config2.workspaces.locking)"

    print "\nSecurity:"
    print $"  Encryption at rest:"
    print $"    ($mode1): ($config1.security.encryption_at_rest)"
    print $"    ($mode2): ($config2.security.encryption_at_rest)"
    print $"  Encryption in transit:"
    print $"    ($mode1): ($config1.security.encryption_in_transit)"
    print $"    ($mode2): ($config2.security.encryption_in_transit)"

    {
        mode1: $mode1
        mode2: $mode2
        comparison: {
            authentication: {
                mode1: $config1.authentication.type
                mode2: $config2.authentication.type
                different: ($config1.authentication.type != $config2.authentication.type)
            }
            deployment: {
                mode1: $config1.services.orchestrator.deployment
                mode2: $config2.services.orchestrator.deployment
                different: ($config1.services.orchestrator.deployment != $config2.services.orchestrator.deployment)
            }
        }
    }
}

# =============================================================================
# Helper Functions
# =============================================================================

def get-mode-config-path [] -> string {
    let workspace_config = $env.PROVISIONING_WORKSPACE_CONFIG? | default (
        $env.HOME | path join ".provisioning" "config"
    )

    $workspace_config | path join "active-mode.yaml"
}

def get-modes-dir [] -> string {
    $env.PROVISIONING_PROJECT_ROOT? | default (pwd) | path join "workspace" "config" "modes"
}

def get-mode-file [mode: string] -> string {
    let modes_dir = get-modes-dir
    $modes_dir | path join $"($mode).yaml"
}

def is-current-mode [mode: string] -> bool {
    let current = (mode current).mode
    $current == $mode
}

def is-interactive [] -> bool {
    (term size).columns > 0
}

def validate-services [services: record] -> list<record> {
    mut results = []

    # Check orchestrator
    if ("orchestrator" in $services) {
        $results = ($results | append {
            check: "Service: orchestrator"
            status: "pass"
        })

        if ($services.orchestrator.deployment in ["local", "remote", "k8s"]) {
            $results = ($results | append {
                check: "Orchestrator deployment valid"
                status: "pass"
            })
        } else {
            $results = ($results | append {
                check: "Orchestrator deployment valid"
                status: "fail"
                message: $"Invalid deployment: ($services.orchestrator.deployment)"
            })
        }
    } else {
        $results = ($results | append {
            check: "Service: orchestrator"
            status: "fail"
            message: "Orchestrator service not configured"
        })
    }

    # Check OCI registry
    if ("oci-registry" in $services) {
        $results = ($results | append {
            check: "Service: oci-registry"
            status: "pass"
        })

        if ($services.oci-registry.deployment in ["local", "remote", "disabled"]) {
            $results = ($results | append {
                check: "OCI registry deployment valid"
                status: "pass"
            })
        }
    }

    $results
}

def validate-authentication [auth: record] -> list<record> {
    mut results = []

    if ("type" in $auth) {
        let valid_types = ["none", "token", "mtls", "oauth", "kms"]

        if ($auth.type in $valid_types) {
            $results = ($results | append {
                check: "Authentication type valid"
                status: "pass"
            })
        } else {
            $results = ($results | append {
                check: "Authentication type valid"
                status: "fail"
                message: $"Invalid auth type: ($auth.type)"
            })
        }
    } else {
        $results = ($results | append {
            check: "Authentication type"
            status: "fail"
            message: "Authentication type not specified"
        })
    }

    $results
}

def validate-extensions [extensions: record] -> list<record> {
    mut results = []

    if ("source" in $extensions) {
        let valid_sources = ["local", "gitea", "oci", "mixed"]

        if ($extensions.source in $valid_sources) {
            $results = ($results | append {
                check: "Extension source valid"
                status: "pass"
            })
        } else {
            $results = ($results | append {
                check: "Extension source valid"
                status: "fail"
                message: $"Invalid source: ($extensions.source)"
            })
        }
    }

    $results
}

def show-mode-next-steps [mode: string] -> nothing {
    print $"\n✓ Switched to '($mode)' mode\n"

    match $mode {
        "solo" => {
            print "Next steps:"
            print "  1. Start orchestrator: cd provisioning/platform/orchestrator && ./scripts/start-orchestrator.nu"
            print "  2. (Optional) Start OCI registry: provisioning mode oci-registry start"
            print "  3. Begin development: provisioning server create --check"
        }
        "multi-user" => {
            print "Next steps:"
            print "  1. Authenticate: provisioning auth login"
            print "  2. Lock workspace: provisioning workspace lock"
            print "  3. Pull extensions from OCI: provisioning extension pull"
            print "  4. Check quota: provisioning quota show"
        }
        "cicd" => {
            print "Next steps:"
            print "  1. Ensure CI/CD environment variables are set"
            print "  2. Token must be available at: /var/run/secrets/provisioning/token"
            print "  3. Run validation: provisioning validate --all"
            print "  4. Execute pipeline: provisioning server create --check"
        }
        "enterprise" => {
            print "Next steps:"
            print "  1. Ensure mTLS certificates are provisioned"
            print "  2. Verify Kubernetes connectivity: kubectl get pods -n provisioning-system"
            print "  3. Check Harbor access: docker login harbor.enterprise.local"
            print "  4. Review compliance policies: provisioning policy list"
            print "  5. Request workspace approval: provisioning workspace request"
        }
    }
}

def start-oci-registry [config: record] -> nothing {
    let oci_config = $config.services.oci-registry
    let data_dir = $oci_config.data_dir | str replace "~" $env.HOME

    # Create data directory if not exists
    if not ($data_dir | path exists) {
        mkdir $data_dir
        log-info $"Created OCI registry data directory: ($data_dir)"
    }

    # Check if already running
    let status_check = (do {
        http get $"http://($oci_config.endpoint):($oci_config.port)/v2/"
    } | complete)

    if $status_check.exit_code == 0 {
        log-warning "OCI registry already running"
        return
    }

    # Start registry (implementation depends on registry type)
    match $oci_config.type {
        "zot" => { start-zot-registry $oci_config }
        "distribution" => { start-distribution-registry $oci_config }
        _ => {
            log-error $"Unsupported registry type for local deployment: ($oci_config.type)"
        }
    }
}

def stop-oci-registry [config: record] -> nothing {
    log-info "Stopping OCI registry..."
    # Implementation depends on how registry was started
    # Could use PID file, systemd, or Docker
}

def oci-registry-status [config: record] -> nothing {
    let oci_config = $config.services.oci-registry

    let status_check = (do {
        http get $"http://($oci_config.endpoint):($oci_config.port)/v2/"
    } | complete)

    if $status_check.exit_code == 0 {
        print "OCI Registry: Running"
        print $"  Endpoint: ($oci_config.endpoint):($oci_config.port)"
        print $"  Type: ($oci_config.type)"
    } else {
        print "OCI Registry: Not running"
    }
}

def oci-registry-logs [config: record] -> nothing {
    let log_file = $config.services.oci-registry.log_file? | default (
        $env.HOME | path join ".provisioning" "oci-registry" "registry.log"
    )

    if ($log_file | path exists) {
        open $log_file
    } else {
        log-warning $"Log file not found: ($log_file)"
    }
}

def start-zot-registry [config: record] -> nothing {
    log-info "Starting Zot OCI registry..."
    # Implementation would start Zot binary with config
}

def start-distribution-registry [config: record] -> nothing {
    log-info "Starting Docker Distribution registry..."
    # Implementation would start distribution binary
}
