# VM Persistence Management (Phase 2)
#
# Manages permanent and temporary VMs with lifecycle tracking.
# Rule 1: Single purpose, Rule 4: Pure functions, Rule 5: Atomic operations
# Error handling: Result pattern (hybrid, do/complete for bash operations)

use ../result.nu *
use ./persistence.nu *
use ./lifecycle.nu *

export def "register-permanent-vm" [
    vm_config: record             # VM configuration
]: record {
    """
    Register a VM as permanent (persists across reboots).

    Permanent VMs are automatically started on host reboot.
    """

    if not ($vm_config.permanent // false) {
        return {
            success: false
            error: "VM must have permanent=true"
        }
    }

    # Create persistence record
    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")
    let persistence_info = {
        vm_name: $vm_config.name
        mode: "permanent"
        created_at: $now
        auto_start: true
        restart_policy: "always"
        start_order: 100
    }

    # Save persistence data using json-write helper (no inline try-catch)
    let persist_file = (get-persistence-file $vm_config.name)
    let write_result = (json-write $persist_file $persistence_info)

    # Guard: Check write result
    if (is-err $write_result) {
        return {success: false, error: $write_result.err}
    }

    {success: true, vm_name: $vm_config.name, message: "Registered as permanent VM"}
}

export def "register-temporary-vm" [
    vm_config: record             # VM configuration
    ttl_hours: int = 24           # Time to live
]: record {
    """
    Register a VM as temporary (auto-cleanup after TTL).

    Temporary VMs are automatically deleted after specified hours.
    """

    if not ($vm_config.temporary // false) {
        return {
            success: false
            error: "VM must have temporary=true"
        }
    }

    # Calculate cleanup time
    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")
    let cleanup_time = (
        $now
        + (($ttl_hours * 60 * 60) * 1_000_000_000)  # Convert to nanoseconds
    )

    let persistence_info = {
        vm_name: $vm_config.name
        mode: "temporary"
        created_at: $now
        ttl_hours: $ttl_hours
        scheduled_cleanup_at: $cleanup_time
        auto_cleanup: true
        cleanup_status: "pending"
    }

    let persist_file = (get-persistence-file $vm_config.name)
    let write_result = (json-write $persist_file $persistence_info)

    # Guard: Check write result
    if (is-err $write_result) {
        return {success: false, error: $write_result.err}
    }

    {
        success: true
        vm_name: $vm_config.name
        ttl_hours: $ttl_hours
        cleanup_scheduled_at: $cleanup_time
        message: $"Registered as temporary VM (cleanup in ($ttl_hours) hours)"
    }
}

export def "get-vm-persistence-info" [
    vm_name: string               # VM name
]: record {
    """Get persistence information for a VM"""

    let persist_file = (get-persistence-file $vm_name)

    # Guard: File exists check
    if not ($persist_file | path exists) {
        return {vm_name: $vm_name, mode: "unknown", error: "No persistence info found"}
    }

    # Read using json-read helper (no inline try-catch)
    (json-read $persist_file)
    | match-result
        {|data| $data}  # On success, return data
        {|_err| {vm_name: $vm_name, mode: "unknown", error: "No persistence info found"}}  # On error, return default
}

export def "list-permanent-vms" []: table {
    """List all permanent VMs"""

    let persist_dir = (get-persistence-dir)

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

    # Use do/complete for bash command (no try-catch)
    let ls_result = (do {
        bash -c $"ls -1 ($persist_dir)/*.json 2>/dev/null"
    } | complete)

    if $ls_result.exit_code != 0 {
        return []
    }

    $ls_result.stdout
    | lines
    | where {|f| ($f | length) > 0}
    | map {|f|
        # Guard: Check if file can be opened and parsed as JSON
        let json_result = (do { open $f | from json } | complete)
        if $json_result.exit_code == 0 {
            let data = ($json_result.stdout)
            if ($data.mode // "unknown") == "permanent" {
                $data
            } else {
                null
            }
        } else {
            null
        }
    }
    | compact
}

export def "list-temporary-vms" []: table {
    """List all temporary VMs"""

    let persist_dir = (get-persistence-dir)

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

    # Use do/complete for bash command (no try-catch)
    let ls_result = (do {
        bash -c $"ls -1 ($persist_dir)/*.json 2>/dev/null"
    } | complete)

    if $ls_result.exit_code != 0 {
        return []
    }

    $ls_result.stdout
    | lines
    | where {|f| ($f | length) > 0}
    | map {|f|
        # Guard: Check if file can be opened and parsed as JSON
        let json_result = (do { open $f | from json } | complete)
        if $json_result.exit_code == 0 {
            let data = ($json_result.stdout)
            if ($data.mode // "unknown") == "temporary" {
                $data
            } else {
                null
            }
        } else {
            null
        }
    }
    | compact
}

export def "find-expired-vms" []: table {
    """Find temporary VMs that have expired (TTL exceeded)"""

    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")
    let temp_vms = (list-temporary-vms)

    $temp_vms
    | filter {|vm|
        ($vm.scheduled_cleanup_at // 0) <= $now
    }
}

export def "cleanup-expired-vms" [
    --dry-run = false             # Dry-run mode
    --force = false               # Force cleanup
]: record {
    """Clean up expired temporary VMs"""

    let expired = (find-expired-vms)

    if ($expired | length) == 0 {
        return {
            success: true
            cleaned_up: 0
            message: "No VMs to clean up"
        }
    }

    let results = (
        $expired
        | map {|vm|
            let delete_result = (
                if $dry_run {
                    {
                        vm_name: $vm.vm_name
                        success: true
                        message: "[DRY-RUN] Would delete VM"
                    }
                } else {
                    vm-delete $vm.vm_name --force=$force
                }
            )

            # Update cleanup status
            if $delete_result.success {
                update-cleanup-status $vm.vm_name "completed" | ignore
            } else {
                update-cleanup-status $vm.vm_name "failed" $delete_result.error | ignore
            }

            $delete_result
        }
    )

    let successful = ($results | where success == true | length)

    {
        success: true
        total_expired: ($expired | length)
        cleaned_up: $successful
        failed: (($results | length) - $successful)
        details: $results
    }
}

export def "get-vm-uptime" [
    vm_name: string               # VM name
]: record {
    """Get VM uptime since creation"""

    let persist_info = (get-vm-persistence-info $vm_name)
    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")

    if ("created_at" in $persist_info) {
        let uptime_seconds = ($now - $persist_info.created_at)
        let uptime_hours = ($uptime_seconds / 3600)
        let uptime_days = ($uptime_hours / 24)

        {
            vm_name: $vm_name
            created_at: $persist_info.created_at
            uptime_seconds: $uptime_seconds
            uptime_hours: $uptime_hours
            uptime_days: $uptime_days
            formatted: $"($uptime_days | floor)d ($uptime_hours | floor)h ($uptime_seconds % 3600 | floor)s"
        }
    } else {
        {
            vm_name: $vm_name
            error: "Cannot determine creation time"
        }
    }
}

export def "get-vm-time-to-cleanup" [
    vm_name: string               # VM name
]: record {
    """Get time remaining until cleanup for temporary VM"""

    let persist_info = (get-vm-persistence-info $vm_name)
    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")

    if ($persist_info.mode // "") != "temporary" {
        return {
            vm_name: $vm_name
            error: "VM is not temporary"
        }
    }

    if not ("scheduled_cleanup_at" in $persist_info) {
        return {
            vm_name: $vm_name
            error: "Cleanup not scheduled"
        }
    }

    let cleanup_time = $persist_info.scheduled_cleanup_at
    let time_remaining = ($cleanup_time - $now)

    if $time_remaining <= 0 {
        return {
            vm_name: $vm_name
            status: "expired"
            time_remaining_seconds: 0
        }
    }

    let hours = ($time_remaining / 3600_000_000_000)
    let minutes = (($time_remaining / 60_000_000_000) % 60)

    {
        vm_name: $vm_name
        status: "active"
        time_remaining_seconds: ($time_remaining / 1_000_000_000)
        time_remaining_formatted: $"($hours | floor)h ($minutes | floor)m"
        scheduled_cleanup_at: $cleanup_time
    }
}

export def "extend-vm-ttl" [
    vm_name: string               # VM name
    additional_hours: int         # Hours to add
]: record {
    """Extend TTL for a temporary VM"""

    let persist_info = (get-vm-persistence-info $vm_name)

    if ($persist_info.mode // "") != "temporary" {
        return {
            success: false
            error: "VM is not temporary"
        }
    }

    let current_cleanup_time = ($persist_info.scheduled_cleanup_at // 0)
    let new_cleanup_time = (
        $current_cleanup_time
        + (($additional_hours * 60 * 60) * 1_000_000_000)
    )

    let updated_info = (
        $persist_info
        | upsert scheduled_cleanup_at $new_cleanup_time
    )

    let persist_file = (get-persistence-file $vm_name)

    # Use do/complete for bash command (no try-catch)
    let write_result = (do {
        bash -c $"cat > ($persist_file) << 'EOF'\n($updated_info | to json)\nEOF"
    } | complete)

    if $write_result.exit_code != 0 {
        return {
            success: false
            error: $write_result.stderr
        }
    }

    {
        success: true
        vm_name: $vm_name
        additional_hours: $additional_hours
        new_cleanup_time: $new_cleanup_time
        message: $"Extended TTL by ($additional_hours) hours"
    }
}

def get-persistence-dir []: string {
    """Get persistence directory"""
    $"{{paths.workspace}}/vms/persistence"
}

def get-persistence-file [vm_name: string]: string {
    """Get persistence file for VM"""
    $"(get-persistence-dir)/($vm_name).json"
}

def update-cleanup-status [
    vm_name: string
    status: string
    error?: string
]: record {
    """Update cleanup status in persistence file"""

    let persist_info = (get-vm-persistence-info $vm_name)
    let now = (now | format date "%Y-%m-%dT%H:%M:%SZ")

    let updated = (
        $persist_info
        | upsert cleanup_status $status
        | upsert last_cleanup_attempt $now
        | if ($error != null) {
            upsert cleanup_error $error
        } else {
            .
        }
    )

    let persist_file = (get-persistence-file $vm_name)

    # Use do/complete for bash command (no try-catch)
    let write_result = (do {
        bash -c $"cat > ($persist_file) << 'EOF'\n($updated | to json)\nEOF"
    } | complete)

    if $write_result.exit_code != 0 {
        return {success: false, error: $write_result.stderr}
    }

    {success: true}
}

export def "get-vm-persistence-stats" []: record {
    """Get statistics about persistent VMs"""

    let permanent = (list-permanent-vms)
    let temporary = (list-temporary-vms)
    let expired = (find-expired-vms)

    {
        total_vms: (($permanent | length) + ($temporary | length))
        permanent_vms: ($permanent | length)
        temporary_vms: ($temporary | length)
        expired_vms: ($expired | length)
        auto_cleanup_enabled: ($temporary | where auto_cleanup == true | length)
    }
}
