# Network Management System (Phase 4)
#
# Manages virtual networks, VLANs, and network policies.
# Rule 1: Single purpose, Rule 5: Atomic operations
# Error handling: do/complete pattern for bash commands (no try-catch)

export def "network-create" [
    name: string                                 # Network name
    subnet: string                               # Network subnet (CIDR)
    --type: string = "bridge"                    # Network type
    --gateway: string = ""                       # Gateway IP
    --vlan-id: int = 0                           # VLAN ID
    --dhcp = true                                # Enable DHCP
]: record {
    """
    Create a virtual network for VMs and containers.

    Supports bridge, overlay, and VLAN networks.
    """

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

    if ($subnet | is-empty) {
        return {success: false, error: "Subnet required"}
    }

    let network_dir = (get-networks-directory)
    bash -c $"mkdir -p ($network_dir)" | complete

    let network_meta = {
        name: $name
        type: $type
        subnet: $subnet
        gateway: (if ($gateway | is-empty) {calculate-gateway $subnet} else {$gateway})
        vlan_id: $vlan_id
        dhcp_enabled: $dhcp
        created_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
        status: "created"
    }

    # Create network bridge or overlay (no try-catch)
    if $type == "bridge" {
        let link_result = (do {
            bash -c $"ip link add ($name) type bridge"
        } | complete)
        if $link_result.exit_code != 0 {
            return {success: false, error: $"Failed to create bridge: ($link_result.stderr)"}
        }

        let addr_result = (do {
            bash -c $"ip addr add ($network_meta.gateway)/24 dev ($name)"
        } | complete)
        if $addr_result.exit_code != 0 {
            return {success: false, error: $"Failed to add address: ($addr_result.stderr)"}
        }

        let up_result = (do {
            bash -c $"ip link set ($name) up"
        } | complete)
        if $up_result.exit_code != 0 {
            return {success: false, error: $"Failed to bring up network: ($up_result.stderr)"}
        }
    }

    # Save metadata
    let save_result = (do {
        bash -c $"cat > ($network_dir)/($name).json << 'EOF'\n($network_meta | to json)\nEOF"
    } | complete)
    if $save_result.exit_code != 0 {
        return {success: false, error: $"Failed to save network metadata: ($save_result.stderr)"}
    }

    {
        success: true
        network: $name
        subnet: $subnet
        gateway: $network_meta.gateway
        vlan_id: $vlan_id
    }
}

export def "network-list" []: table {
    """
    List all virtual networks.
    """

    let network_dir = (get-networks-directory)

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

    bash -c $"ls -1 ($network_dir)/*.json 2>/dev/null"
    | lines
    | each {|file|
        # Guard: Check if file can be opened and parsed as JSON
        let json_result = (do { open $file | from json } | complete)
        if $json_result.exit_code == 0 {
            let meta = ($json_result.stdout)
            {
                name: $meta.name
                type: $meta.type
                subnet: $meta.subnet
                gateway: $meta.gateway
                vlan_id: $meta.vlan_id
                dhcp: $meta.dhcp_enabled
                created: $meta.created_at
            }
        } else {
            null
        }
    }
    | compact
}

export def "network-info" [
    name: string                                 # Network name
]: record {
    """
    Get detailed network information.
    """

    let network_dir = (get-networks-directory)
    let meta_file = $"($network_dir)/($name).json"

    if (not ($meta_file | path exists)) {
        return {success: false, error: "Network not found"}
    }

    # Load network metadata (no try-catch)
    let meta_result = (do { open $meta_file | from json } | complete)
    if $meta_result.exit_code != 0 {
        return {success: false, error: $"Failed to load network metadata: ($meta_result.stderr)"}
    }

    let meta = ($meta_result.stdout)
    let connected = (get-network-connections $name)

    {
        success: true
        name: $meta.name
        type: $meta.type
        subnet: $meta.subnet
        gateway: $meta.gateway
        vlan_id: $meta.vlan_id
        dhcp_enabled: $meta.dhcp_enabled
        created: $meta.created_at
        connected_vms: ($connected | length)
        vm_list: $connected
    }
}

export def "network-connect" [
    network_name: string                        # Network name
    vm_name: string                             # VM name
    --static-ip: string = ""                    # Static IP
]: record {
    """
    Connect VM to a network.
    """

    let network_dir = (get-networks-directory)
    let meta_file = $"($network_dir)/($network_name).json"

    if (not ($meta_file | path exists)) {
        return {success: false, error: "Network not found"}
    }

    # Load metadata and connect VM (no try-catch)
    let meta_result = (do { open $meta_file | from json } | complete)
    if $meta_result.exit_code != 0 {
        return {success: false, error: $"Failed to load network metadata: ($meta_result.stderr)"}
    }

    let meta = ($meta_result.stdout)
    let ip = (if ($static_ip | is-empty) {allocate-dhcp-ip $network_name} else {$static_ip})

    # Record connection
    let connection = {
        vm_name: $vm_name
        ip_address: $ip
        connected_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
    }

    let mkdir_result = (do {
        bash -c $"mkdir -p ($network_dir)/connections"
    } | complete)
    if $mkdir_result.exit_code != 0 {
        return {success: false, error: $"Failed to create connections directory: ($mkdir_result.stderr)"}
    }

    let append_result = (do {
        bash -c $"cat >> ($network_dir)/connections/($network_name).txt << 'EOF'\n($vm_name)|($ip)\nEOF"
    } | complete)
    if $append_result.exit_code != 0 {
        return {success: false, error: $"Failed to record connection: ($append_result.stderr)"}
    }

    {
        success: true
        network: $network_name
        vm: $vm_name
        ip_address: $ip
    }
}

export def "network-disconnect" [
    network_name: string                        # Network name
    vm_name: string                             # VM name
]: record {
    """
    Disconnect VM from network.
    """

    let network_dir = (get-networks-directory)
    let connections_file = $"($network_dir)/connections/($network_name).txt"

    if (not ($connections_file | path exists)) {
        return {success: false, error: "No connections found"}
    }

    # Disconnect VM from network (no try-catch)
    let disconnect_result = (do {
        bash -c $"grep -v ($vm_name) ($connections_file) > ($connections_file).tmp && mv ($connections_file).tmp ($connections_file)"
    } | complete)

    if $disconnect_result.exit_code != 0 {
        return {success: false, error: $"Failed to disconnect VM: ($disconnect_result.stderr)"}
    }

    {
        success: true
        message: "VM disconnected from network"
    }
}

export def "network-policy-create" [
    name: string                                 # Policy name
    --direction: string = "both"                 # Direction (inbound/outbound/both)
    --protocol: string = "tcp"                   # Protocol (tcp/udp/icmp/all)
    --source: string = "any"                     # Source CIDR or name
    --destination: string = "any"                # Destination CIDR or name
    --port-range: string = "any"                 # Port range
    --action: string = "allow"                   # Action (allow/deny/log)
]: record {
    """
    Create a network policy for traffic control.
    """

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

    let policy_dir = (get-policies-directory)
    bash -c $"mkdir -p ($policy_dir)" | complete

    let policy = {
        name: $name
        direction: $direction
        protocol: $protocol
        source: $source
        destination: $destination
        port_range: $port_range
        action: $action
        created_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
    }

    # Save network policy (no try-catch)
    let save_result = (do {
        bash -c $"cat > ($policy_dir)/($name).json << 'EOF'\n($policy | to json)\nEOF"
    } | complete)

    if $save_result.exit_code != 0 {
        return {success: false, error: $"Failed to save policy: ($save_result.stderr)"}
    }

    {
        success: true
        policy: $name
        direction: $direction
        protocol: $protocol
        action: $action
    }
}

export def "network-policy-list" []: table {
    """
    List all network policies.
    """

    let policy_dir = (get-policies-directory)

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

    bash -c $"ls -1 ($policy_dir)/*.json 2>/dev/null"
    | lines
    | each {|file|
        # Guard: Check if file can be opened and parsed as JSON
        let json_result = (do { open $file | from json } | complete)
        if $json_result.exit_code == 0 {
            let policy = ($json_result.stdout)
            {
                name: $policy.name
                direction: $policy.direction
                protocol: $policy.protocol
                source: $policy.source
                destination: $policy.destination
                action: $policy.action
                created: $policy.created_at
            }
        } else {
            null
        }
    }
    | compact
}

export def "network-stats" []: record {
    """
    Get network system statistics.
    """

    let networks = (network-list)
    let policies = (network-policy-list)

    let total_connections = (
        bash -c $"find {{paths.workspace}}/vms/networks/connections -name '*.txt' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}'"
        | into int
    )

    {
        total_networks: ($networks | length)
        total_policies: ($policies | length)
        total_connections: ($total_connections ?? 0)
        networks: $networks
        policies: $policies
    }
}

export def "vlan-create" [
    vlan_id: int                                 # VLAN ID (1-4094)
    network_name: string                         # VLAN name
    subnet: string                               # Subnet CIDR
]: record {
    """
    Create a VLAN (Virtual LAN).

    Isolated network segments with tag-based traffic.
    """

    if ($vlan_id < 1 or $vlan_id > 4094) {
        return {success: false, error: "VLAN ID must be 1-4094"}
    }

    network-create $network_name $subnet --type vlan --vlan-id $vlan_id
}

export def "vlan-list" []: table {
    """
    List all VLANs.
    """

    let networks = (network-list)

    $networks
    | where {|n| $n.type == "vlan" or $n.vlan_id > 0}
}

def get-networks-directory []: string {
    """Get networks directory path"""
    "{{paths.workspace}}/vms/networks"
}

def get-policies-directory []: string {
    """Get policies directory path"""
    "{{paths.workspace}}/vms/policies"
}

def calculate-gateway [subnet: string]: string {
    """Calculate gateway IP from subnet"""
    # For subnet like 192.168.1.0/24, gateway is .1
    let parts = ($subnet | split row ".")
    $"($parts.0).($parts.1).($parts.2).1"
}

def allocate-dhcp-ip [network: string]: string {
    """Allocate DHCP IP for VM"""
    # Simplified - in production would use proper DHCP server
    let rand = $env.RANDOM
    $"192.168.100.($rand % 200 + 50)"
}

def get-network-connections [name: string]: list<string> {
    """Get VMs connected to network"""
    let network_dir = (get-networks-directory)
    let connections_file = $"($network_dir)/connections/($name).txt"

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

    bash -c $"cut -d'|' -f1 ($connections_file)"
    | lines
}
