# VM Lifecycle Management
#
# Higher-level VM operations: create, start, stop, delete with state tracking.
# Rule 1: Single purpose, Rule 4: Pure functions, Rule 5: Atomic operations

# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/vm/backend_libvirt.nu [
    libvirt-create-disk libvirt-create-vm libvirt-delete-vm libvirt-get-vm-info
    libvirt-get-vm-ip libvirt-list-vms libvirt-start-vm libvirt-stop-vm
]
use lib_provisioning/vm/persistence.nu [
    get-vm-state record-vm-creation remove-vm-state update-vm-state
]

export def "vm-create" [
    vm_config: record             # VM configuration (from Nickel)
    --backend: string = "libvirt" # Backend to use
]: record {
    """
    Create a virtual machine.

    Creates VM disk, defines in hypervisor, and records state.

    Examples:
        # Create temporary test VM
        vm-create {
            name: "test-k8s"
            cpu: 4
            memory_mb: 8192
            temporary: true
            auto_cleanup: true
        }

        # Create permanent dev VM
        vm-create {
            name: "dev-rust"
            cpu: 8
            memory_mb: 16384
            disk_gb: 50
            permanent: true
        }
    """

    # Validation (Rule 3: Early return)
    let validation = (validate-vm-config $vm_config)
    if not $validation.valid {
        return {
            success: false
            error: $validation.error
        }
    }

    # Create disk
    let disk_result = (libvirt-create-disk $vm_config.name $vm_config.disk_gb)
    if not $disk_result.success {
        return {
            success: false
            error: $"Disk creation failed: ($disk_result.error)"
        }
    }

    # Define VM in libvirt
    let define_result = (libvirt-create-vm $vm_config)
    if not $define_result.success {
        # Cleanup disk on failure
        bash -c $"rm -f ($disk_result.path)"
        return $define_result
    }

    # Record VM state (Rule 5: Atomic operation)
    let state_result = (record-vm-creation $vm_config)
    if not $state_result.success {
        # Try to cleanup on failure
        libvirt-delete-vm $vm_config.name | ignore
        return $state_result
    }

    {
        success: true
        vm_name: $vm_config.name
        vm_id: $define_result.vm_id
        message: $"VM ($vm_config.name) created successfully"
        disk_path: $disk_result.path
    }
}

export def "vm-start" [
    vm_name: string               # VM name
]: record {
    """Start a virtual machine"""

    if ($vm_name | is-empty) {
        return {success: false, error: "VM name required"}
    }

    let start_result = (libvirt-start-vm $vm_name)
    if not $start_result.success {
        return $start_result
    }

    # Update state
    update-vm-state $vm_name "running" | ignore

    $start_result
}

export def "vm-stop" [
    vm_name: string               # VM name
    --force = false               # Force shutdown
]: record {
    """Stop a virtual machine"""

    if ($vm_name | is-empty) {
        return {success: false, error: "VM name required"}
    }

    let stop_result = (libvirt-stop-vm $vm_name --force=$force)
    if not $stop_result.success {
        return $stop_result
    }

    # Update state
    update-vm-state $vm_name "stopped" | ignore

    $stop_result
}

export def "vm-delete" [
    vm_name: string               # VM name
    --force = false               # Force deletion
]: record {
    """Delete a virtual machine"""

    if ($vm_name | is-empty) {
        return {success: false, error: "VM name required"}
    }

    # Delete from libvirt
    let delete_result = (libvirt-delete-vm $vm_name)
    if not $delete_result.success {
        return $delete_result
    }

    # Remove state record
    remove-vm-state $vm_name | ignore

    $delete_result
}

export def "vm-list" [
    --permanent = false           # List only permanent VMs
    --temporary = false           # List only temporary VMs
    --running = false             # List only running VMs
]: table {
    """List virtual machines"""

    let all_vms = (libvirt-list-vms)

    let vms = (
        $all_vms
        | each {|vm|
            let state = (get-vm-state $vm.name)
            {
                name: $vm.name
                status: $vm.state
                permanent: ($state.permanent 2>/dev/null ?? false)
                temporary: ($state.temporary 2>/dev/null ?? false)
                cpu: ($state.cpu 2>/dev/null ?? "unknown")
                memory_mb: ($state.memory_mb 2>/dev/null ?? "unknown")
            }
        }
    )

    # Apply filters
    let filtered = (
        $vms
        | if $permanent {
            where permanent == true
        } else if $temporary {
            where temporary == true
        } else {
            .
        }
        | if $running {
            where status == "running"
        } else {
            .
        }
    )

    $filtered
}

export def "vm-info" [
    vm_name: string               # VM name
]: record {
    """Get detailed VM information"""

    if ($vm_name | is-empty) {
        return {error: "VM name required"}
    }

    let libvirt_info = (libvirt-get-vm-info $vm_name)
    let state_info = (get-vm-state $vm_name)
    let ip_address = (libvirt-get-vm-ip $vm_name)

    {
        name: $vm_name
        status: $libvirt_info.state
        id: $libvirt_info.id
        cpu_cores: $libvirt_info.cpu_cores
        memory_mb: $libvirt_info.memory_mb
        ip_address: $ip_address
        permanent: ($state_info.permanent 2>/dev/null ?? false)
        temporary: ($state_info.temporary 2>/dev/null ?? false)
        created_at: ($state_info.created_at 2>/dev/null ?? "unknown")
    }
}

def validate-vm-config [config: record]: record {
    """Validate VM configuration"""

    # Name validation
    if ($config.name | is-empty) {
        return {valid: false, error: "VM name required"}
    }

    if not ($config.name | str match '^[a-z0-9][a-z0-9-]*[a-z0-9]$') {
        return {
            valid: false
            error: "Invalid VM name format"
        }
    }

    # Resource validation
    if ($config.cpu // 0) <= 0 or ($config.cpu // 0) > 64 {
        return {valid: false, error: "CPU must be 1-64"}
    }

    if ($config.memory_mb // 0) < 512 {
        return {valid: false, error: "Memory must be >= 512MB"}
    }

    if ($config.disk_gb // 0) < 5 {
        return {valid: false, error: "Disk must be >= 5GB"}
    }

    # Lifecycle validation
    if ($config.permanent and $config.temporary) {
        return {valid: false, error: "Cannot be both permanent and temporary"}
    }

    {valid: true}
}
