#!/usr/bin/env nu

# Port Management Script for Provisioning Platform
# Centralizes port configuration and updates across all services

const DEFAULT_PORTS = {
    orchestrator: 9090,
    control_center: 9080,
    api_gateway: 9083,
    mcp_server: 9082,
    oci_registry: 5000,
    coredns: 5353,
    gitea: 3000,
    frontend: 3001,
    surrealdb: 8000,
    redis: 6379,
    postgresql: 5432
}

# Show current port configuration
export def "main show" [] {
    print "📊 Current Port Configuration\n"

    let config = load_current_config

    $config | each {|service|
        print $"  ($service.name | fill -a right -c ' ' -w 20): ($service.port) \(($service.status)\)"
    }
}

# Check if ports are in use
export def "main check" [] {
    print "🔍 Checking port availability\n"

    for service in ($DEFAULT_PORTS | transpose key value) {
        let port = $service.value
        let in_use = (is_port_in_use $port)

        if $in_use {
            let process = (get_process_on_port $port)
            print $"  ⚠️  ($service.key | fill -a right -c ' ' -w 20): Port ($port) IN USE by ($process)"
        } else {
            print $"  ✅  ($service.key | fill -a right -c ' ' -w 20): Port ($port) available"
        }
    }
}

# Update port configuration across all files
export def "main update" [
    service: string    # Service name (orchestrator, control_center, etc)
    new_port: int      # New port number
    --apply            # Apply changes (default is dry-run)
] {
    if $service not-in ($DEFAULT_PORTS | columns) {
        error make {msg: $"Unknown service: ($service). Available: ($DEFAULT_PORTS | columns | str join ', ')"}
    }

    let old_port = ($DEFAULT_PORTS | get $service)

    print $"📝 Updating ($service) port: ($old_port) → ($new_port)\n"

    # Get files to update
    let files = (get_files_for_service $service)

    if ($files | is-empty) {
        print "  ℹ️  No configuration files found for this service"
        return
    }

    print $"  Found ($files | length) files to update:\n"

    for file in $files {
        let changes = (preview_changes $file $old_port $new_port)

        if ($changes | length) > 0 {
            print $"  📄 ($file)"
            print $"     Changes: ($changes | length) line\(s\)"

            if $apply {
                update_file $file $old_port $new_port $service
                print "     ✅ Applied"
            } else {
                print "     ⏭️  Dry-run \(use --apply to apply\)"
            }
        }
    }

    if not $apply {
        print $"\n💡 Run with --apply to apply changes"
    } else {
        print $"\n✅ Port updated. Remember to rebuild and restart the service!"
    }
}

# Verify port configuration is consistent
export def "main verify" [] {
    print "🔎 Verifying port configuration consistency\n"

    let issues = []

    for service in ($DEFAULT_PORTS | transpose key value) {
        let service_name = $service.key
        let expected_port = $service.value

        let files = (get_files_for_service $service_name)

        for file in $files {
            if ($file | path exists) {
                let content = (open $file)
                let found_ports = (extract_ports_from_file $file $service_name)

                for port in $found_ports {
                    if $port != $expected_port {
                        print $"  ⚠️  ($service_name) in ($file): Found port ($port), expected ($expected_port)"
                    }
                }
            }
        }
    }

    print "\n✅ Verification complete"
}

# Migrate from old ports to new ports
export def "main migrate" [
    --orchestrator: int = 9090    # New orchestrator port
    --control_center: int = 9080  # New control center port
    --apply                       # Apply changes
] {
    print "🔄 Port Migration Tool\n"

    print "Migration plan:"
    print $"  Orchestrator:    8080 → ($orchestrator)"
    print $"  Control Center:  8081 → ($control_center)"
    print ""

    if not $apply {
        print "⚠️  DRY RUN MODE - No changes will be made"
        print "   Use --apply to apply changes\n"
    }

    # Orchestrator
    if $orchestrator != 8080 {
        main update orchestrator $orchestrator --apply=$apply
    }

    # Control Center
    if $control_center != 8081 {
        main update control_center $control_center --apply=$apply
    }

    if $apply {
        print "\n✅ Migration complete!"
        print "\n📋 Next steps:"
        print "  1. Rebuild services: cd provisioning/platform/orchestrator && cargo build --release"
        print "  2. Rebuild services: cd provisioning/platform/control-center && cargo build --release"
        print "  3. Restart services"
    }
}

# Helper: Load current configuration
def load_current_config [] {
    [
        {name: "orchestrator", port: (get_port_from_file "provisioning/platform/orchestrator/config.defaults.toml" "port"), status: "configured"},
        {name: "control_center", port: (get_port_from_file "provisioning/platform/control-center/config.defaults.toml" "port"), status: "configured"},
        {name: "oci_registry", port: 5000, status: "static"},
        {name: "coredns", port: 5353, status: "static"},
        {name: "gitea", port: 3000, status: "static"},
        {name: "surrealdb", port: 8000, status: "static"}
    ]
}

# Helper: Check if port is in use
def is_port_in_use [port: int] {
    let result = (do { lsof -i $":($port)" | complete } | get exit_code)
    $result == 0
}

# Helper: Get process using port
def get_process_on_port [port: int] {
    let result = (do {
        let output = (lsof -i $":($port)" | lines | get 1 | split row -r '\s+')
        $"($output.0) \(PID: ($output.1)\)"
    } | complete)

    if $result.exit_code != 0 {
        "unknown"
    } else {
        $result.stdout
    }
}

# Helper: Get files for a service
def get_files_for_service [service: string] {
    let base = $env.HOME

    match $service {
        "orchestrator" => [
            $"($base)/provisioning/platform/orchestrator/src/lib.rs",
            $"($base)/provisioning/platform/orchestrator/config.defaults.toml",
            $"($base)/provisioning/platform/orchestrator/scripts/start-orchestrator.nu"
        ],
        "control_center" => [
            $"($base)/provisioning/platform/control-center/src/simple_config.rs",
            $"($base)/provisioning/platform/control-center/config.defaults.toml"
        ],
        _ => []
    }
}

# Helper: Preview changes in a file
def preview_changes [file: string, old_port: int, new_port: int] {
    if not ($file | path exists) {
        return []
    }

    let content = (open $file)
    let lines = ($content | lines)

    $lines | enumerate | where {|it|
        ($it.item | str contains $"($old_port)")
    } | get index
}

# Helper: Update file
def update_file [file: string, old_port: int, new_port: int, service: string] {
    let content = (open $file)

    # Different update strategies based on file type
    let updated = if ($file | str ends-with ".rs") {
        # Rust file - careful replacement
        $content | str replace -a $"port = ($old_port)" $"port = ($new_port)"
                | str replace -a $"default_value = \"($old_port)\"" $"default_value = \"($new_port)\""
    } else if ($file | str ends-with ".toml") {
        # TOML file
        $content | str replace -a $"port = ($old_port)" $"port = ($new_port)"
    } else if ($file | str ends-with ".nu") {
        # Nushell file
        $content | str replace -a $"= ($old_port)" $"= ($new_port)"
                | str replace -a $": int = ($old_port)" $": int = ($new_port)"
    } else {
        $content
    }

    $updated | save -f $file
}

# Helper: Get port from TOML file
def get_port_from_file [file: string, key: string] {
    let full_path = ($env.HOME | path join $"project-provisioning/($file)")
    if not ($full_path | path exists) {
        return 0
    }

    let result = (do {
        let content = (open $full_path)
        let match = ($content | lines | find -r $"($key)\\s*=\\s*(\\d+)" | first)
        if ($match | is-empty) {
            return 0
        }
        ($match | parse -r $"($key)\\s*=\\s*(?<port>\\d+)" | get port.0 | into int)
    } | complete)

    if $result.exit_code != 0 {
        0
    } else {
        $result.stdout
    }
}

# Helper: Extract ports from file for service
def extract_ports_from_file [file: string, service: string] {
    let result = (do {
        let content = (open $file)
        let matches = ($content | lines | find -r '\d{4,5}' | parse -r '(?<port>\d{4,5})')
        $matches | get port | into int | uniq
    } | complete)

    if $result.exit_code != 0 {
        []
    } else {
        $result.stdout
    }
}

# Main help
export def main [] {
    print "Port Management for Provisioning Platform\n"
    print "Usage:"
    print "  manage-ports.nu show              - Show current port configuration"
    print "  manage-ports.nu check             - Check if ports are available"
    print "  manage-ports.nu update <service> <port> [--apply]  - Update service port"
    print "  manage-ports.nu verify            - Verify configuration consistency"
    print "  manage-ports.nu migrate [--apply] - Migrate from old to new ports"
    print ""
    print "Examples:"
    print "  manage-ports.nu check"
    print "  manage-ports.nu update orchestrator 9090 --apply"
    print "  manage-ports.nu migrate --orchestrator 9090 --control_center 9080 --apply"
}
