# OrbStack Integration Helpers
# Utilities for interacting with OrbStack machine "provisioning"

use std log

# Connect to OrbStack machine
export def orbstack-connect [] {
    let test_config = (load-test-config)
    let machine_name = $test_config.orbstack.machine_name

    # Verify OrbStack machine exists
    let machines = (orb list | from json)

    if not ($machine_name in ($machines | get name)) {
        error make {
            msg: $"OrbStack machine '($machine_name)' not found"
            label: {
                text: "Machine not found"
            }
        }
    }

    # Return connection info
    {
        machine: $machine_name
        docker_socket: $test_config.orbstack.connection.socket
        network: $test_config.orbstack.network
    }
}

# Run command on OrbStack machine
export def orbstack-run [
    command: string
    --detach: bool = false
] {
    let connection = (orbstack-connect)

    if $detach {
        docker -H $connection.docker_socket run -d $command
    } else {
        docker -H $connection.docker_socket run --rm $command
    }
}

# Execute command in running container
export def orbstack-exec [
    container_name: string
    command: string
] {
    let connection = (orbstack-connect)

    docker -H $connection.docker_socket exec $container_name $command
}

# Deploy platform service to OrbStack
export def orbstack-deploy-service [
    service_name: string
    config: record
] {
    let connection = (orbstack-connect)
    let test_config = (load-test-config)

    log info $"Deploying ($service_name) to OrbStack..."

    match $service_name {
        "orchestrator" => {
            deploy-orchestrator $connection $config
        }
        "coredns" => {
            deploy-coredns $connection $config
        }
        "oci_registry" => {
            deploy-oci-registry $connection $config
        }
        "gitea" => {
            deploy-gitea $connection $config
        }
        "postgres" => {
            deploy-postgres $connection $config
        }
        "prometheus" => {
            deploy-prometheus $connection $config
        }
        "grafana" => {
            deploy-grafana $connection $config
        }
        _ => {
            error make {
                msg: $"Unknown service: ($service_name)"
            }
        }
    }
}

# Deploy orchestrator service
def deploy-orchestrator [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.orchestrator

    # Build orchestrator image if needed
    let orchestrator_path = $"($env.PWD)/provisioning/platform/orchestrator"

    cd $orchestrator_path
    docker -H $connection.docker_socket build -t provisioning-orchestrator:test .

    # Run orchestrator container
    docker -H $connection.docker_socket run -d \
        --name orchestrator \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):($service_config.port)" \
        -v /var/run/docker.sock:/var/run/docker.sock \
        provisioning-orchestrator:test

    log info "Orchestrator deployed successfully"
}

# Deploy CoreDNS service
def deploy-coredns [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.coredns

    # Create CoreDNS configuration
    let coredns_config = $"
.:53 {
    forward . 8.8.8.8 8.8.4.4
    log
    errors
    cache
}

local:53 {
    file /etc/coredns/db.local
    log
    errors
}
"

    # Write config to temp file
    $coredns_config | save -f /tmp/Corefile

    # Run CoreDNS container
    docker -H $connection.docker_socket run -d \
        --name coredns \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):53/udp" \
        -v /tmp/Corefile:/etc/coredns/Corefile \
        coredns/coredns:latest

    log info "CoreDNS deployed successfully"
}

# Deploy OCI registry (Zot or Harbor)
def deploy-oci-registry [connection: record, config: record] {
    let test_config = (load-test-config)
    let use_harbor = ($config.use_harbor? | default false)

    if $use_harbor {
        deploy-harbor $connection $config
    } else {
        deploy-zot $connection $config
    }
}

# Deploy Zot OCI registry
def deploy-zot [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.oci_registry.zot

    # Zot configuration
    let zot_config = {
        storage: {
            rootDirectory: "/var/lib/registry"
        }
        http: {
            address: "0.0.0.0"
            port: 5000
        }
        log: {
            level: "info"
        }
    }

    $zot_config | to json | save -f /tmp/zot-config.json

    # Run Zot container
    docker -H $connection.docker_socket run -d \
        --name oci-registry \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):5000" \
        -v /tmp/zot-config.json:/etc/zot/config.json \
        -v zot-data:/var/lib/registry \
        ghcr.io/project-zot/zot:latest

    log info "Zot OCI registry deployed successfully"
}

# Deploy Harbor OCI registry
def deploy-harbor [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.oci_registry.harbor

    # Harbor requires docker-compose, use Harbor installer
    log info "Deploying Harbor (enterprise mode)..."

    # Download Harbor offline installer
    let harbor_version = "v2.9.0"
    let harbor_url = $"https://github.com/goharbor/harbor/releases/download/($harbor_version)/harbor-offline-installer-($harbor_version).tgz"

    # Note: Full Harbor deployment requires docker-compose and is complex
    # For testing, we'll use a simplified Harbor deployment
    docker -H $connection.docker_socket run -d \
        --name harbor \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):443" \
        -p $"($service_config.ui_port):80" \
        goharbor/harbor-core:$harbor_version

    log info "Harbor OCI registry deployed successfully"
}

# Deploy Gitea service
def deploy-gitea [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.gitea
    let postgres_config = $test_config.services.postgres

    # Run Gitea container
    docker -H $connection.docker_socket run -d \
        --name gitea \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):3000" \
        -p $"($service_config.ssh_port):22" \
        -e USER_UID=1000 \
        -e USER_GID=1000 \
        -e GITEA__database__DB_TYPE=postgres \
        -e $"GITEA__database__HOST=($postgres_config.host):($postgres_config.port)" \
        -e GITEA__database__NAME=gitea \
        -e GITEA__database__USER=$postgres_config.username \
        -e GITEA__database__PASSWD=gitea \
        -v gitea-data:/data \
        gitea/gitea:latest

    log info "Gitea deployed successfully"
}

# Deploy PostgreSQL service
def deploy-postgres [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.postgres

    # Run PostgreSQL container
    docker -H $connection.docker_socket run -d \
        --name postgres \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):5432" \
        -e POSTGRES_USER=$service_config.username \
        -e POSTGRES_PASSWORD=postgres \
        -e POSTGRES_DB=$service_config.database \
        -v postgres-data:/var/lib/postgresql/data \
        postgres:15-alpine

    log info "PostgreSQL deployed successfully"
}

# Deploy Prometheus service
def deploy-prometheus [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.prometheus

    # Prometheus configuration
    let prometheus_config = $"
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'orchestrator'
    static_configs:
      - targets: ['($test_config.services.orchestrator.host):($test_config.services.orchestrator.port)']
"

    $prometheus_config | save -f /tmp/prometheus.yml

    # Run Prometheus container
    docker -H $connection.docker_socket run -d \
        --name prometheus \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):9090" \
        -v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml \
        -v prometheus-data:/prometheus \
        prom/prometheus:latest

    log info "Prometheus deployed successfully"
}

# Deploy Grafana service
def deploy-grafana [connection: record, config: record] {
    let test_config = (load-test-config)
    let service_config = $test_config.services.grafana

    # Run Grafana container
    docker -H $connection.docker_socket run -d \
        --name grafana \
        --network provisioning-net \
        --ip $service_config.host \
        -p $"($service_config.port):3000" \
        -e GF_SECURITY_ADMIN_PASSWORD=admin \
        -v grafana-data:/var/lib/grafana \
        grafana/grafana:latest

    log info "Grafana deployed successfully"
}

# Create Docker network for services
export def orbstack-create-network [] {
    let connection = (orbstack-connect)
    let test_config = (load-test-config)

    # Create custom network
    docker -H $connection.docker_socket network create \
        --subnet $test_config.orbstack.network.subnet \
        --gateway $test_config.orbstack.network.gateway \
        provisioning-net

    log info "Docker network 'provisioning-net' created"
}

# Cleanup OrbStack resources
export def orbstack-cleanup [] {
    let connection = (orbstack-connect)

    log info "Cleaning up OrbStack resources..."

    # Stop and remove all containers
    let containers = [
        "orchestrator"
        "coredns"
        "oci-registry"
        "harbor"
        "gitea"
        "postgres"
        "prometheus"
        "grafana"
    ]

    for container in $containers {
        try {
            docker -H $connection.docker_socket stop $container
            docker -H $connection.docker_socket rm $container
        } catch {
            # Ignore errors if container doesn't exist
        }
    }

    # Remove network
    try {
        docker -H $connection.docker_socket network rm provisioning-net
    } catch {
        # Ignore errors if network doesn't exist
    }

    log info "OrbStack cleanup completed"
}

# Get logs from OrbStack container
export def orbstack-logs [
    container_name: string
    --tail: int = 100
    --follow: bool = false
] {
    let connection = (orbstack-connect)

    if $follow {
        docker -H $connection.docker_socket logs -f --tail $tail $container_name
    } else {
        docker -H $connection.docker_socket logs --tail $tail $container_name
    }
}

# Helper to load test config (copied from test_helpers.nu to avoid circular dependency)
def load-test-config [] {
    let config_path = $"($env.PWD)/provisioning/tests/integration/test_config.yaml"
    open $config_path
}
