# Integration Test Environment Setup
# Deploys platform to OrbStack machine "provisioning" and prepares test environment

use std log
use framework/test_helpers.nu *
use framework/orbstack_helpers.nu *

# Main setup function
export def main [
    --mode: string = "solo"  # solo, multiuser, cicd, enterprise
    --skip-platform-deploy: bool = false
    --skip-test-data: bool = false
] {
    log info "Setting up integration test environment..."
    log info $"Mode: ($mode)"

    # Load test configuration
    let test_config = (load-test-config)

    # Verify OrbStack machine exists
    verify-orbstack-machine

    # Create Docker network
    if not $skip_platform_deploy {
        log info "Creating Docker network..."
        orbstack-create-network
    }

    # Deploy platform services based on mode
    if not $skip_platform_deploy {
        deploy-platform-services $mode $test_config
    }

    # Wait for services to be healthy
    wait-for-platform-services $mode $test_config

    # Initialize test workspace
    initialize-test-workspace $test_config

    # Seed test data
    if not $skip_test_data {
        seed-test-data $mode $test_config
    }

    # Verify platform is ready
    verify-platform-ready $mode $test_config

    log info "Test environment setup completed successfully!"

    # Return environment info
    {
        mode: $mode
        services: (get-deployed-services $mode $test_config)
        workspace: $test_config.test_workspace
        timestamp: (date now)
    }
}

# Verify OrbStack machine exists
def verify-orbstack-machine [] {
    log info "Verifying OrbStack machine..."

    let test_config = (load-test-config)
    let machine_name = $test_config.orbstack.machine_name

    # Check if orb CLI is available
    try {
        orb version | complete
    } catch {
        error make {
            msg: "OrbStack CLI 'orb' not found. Please install OrbStack."
        }
    }

    # List machines
    let machines = (orb list | from json)

    if not ($machine_name in ($machines | get name)) {
        log warning $"OrbStack machine '($machine_name)' not found. Creating..."

        # Create machine
        orb create $machine_name

        log info $"Created OrbStack machine: ($machine_name)"
    } else {
        log info $"OrbStack machine '($machine_name)' found"
    }

    # Verify machine is running
    let machine_status = (orb status $machine_name | from json)

    if $machine_status.state != "running" {
        log info $"Starting OrbStack machine: ($machine_name)"
        orb start $machine_name
    }
}

# Deploy platform services based on mode
def deploy-platform-services [mode: string, test_config: record] {
    log info $"Deploying platform services for mode: ($mode)"

    let mode_config = match $mode {
        "solo" => { $test_config.modes.solo }
        "multiuser" => { $test_config.modes.multiuser }
        "cicd" => { $test_config.modes.cicd }
        "enterprise" => { $test_config.modes.enterprise }
        _ => {
            error make {
                msg: $"Unknown mode: ($mode)"
            }
        }
    }

    # Deploy required services
    for service in $mode_config.services {
        log info $"Deploying service: ($service)"

        let service_config = match $service {
            "oci_registry" => {
                if $mode == "enterprise" {
                    { use_harbor: true }
                } else {
                    { use_harbor: false }
                }
            }
            _ => { {} }
        }

        orbstack-deploy-service $service $service_config
    }
}

# Wait for platform services to be healthy
def wait-for-platform-services [mode: string, test_config: record] {
    log info "Waiting for platform services to be healthy..."

    let mode_config = match $mode {
        "solo" => { $test_config.modes.solo }
        "multiuser" => { $test_config.modes.multiuser }
        "cicd" => { $test_config.modes.cicd }
        "enterprise" => { $test_config.modes.enterprise }
        _ => {
            error make {
                msg: $"Unknown mode: ($mode)"
            }
        }
    }

    # Wait for each service
    for service in $mode_config.services {
        # Skip services that don't have health checks
        if $service in ["oci_registry"] {
            continue
        }

        log info $"Waiting for service: ($service)"

        wait-for-service $service 120
    }

    log info "All services are healthy"
}

# Initialize test workspace
def initialize-test-workspace [test_config: record] {
    log info "Initializing test workspace..."

    let workspace_path = $test_config.test_workspace.path

    # Create workspace directory structure
    mkdir $workspace_path
    mkdir $"($workspace_path)/config"
    mkdir $"($workspace_path)/infra"
    mkdir $"($workspace_path)/extensions"
    mkdir $"($workspace_path)/runtime"

    # Create workspace configuration
    let workspace_config = {
        workspace: {
            name: $test_config.test_workspace.name
            version: "1.0.0"
            created: (date now | format date "%Y-%m-%d")
        }
        settings: {
            provider: $test_config.test_workspace.config.provider
            region: $test_config.test_workspace.config.region
            environment: $test_config.test_workspace.config.environment
        }
        services: {
            orchestrator: $test_config.services.orchestrator
            coredns: $test_config.services.coredns
            oci_registry: $test_config.services.oci_registry
        }
    }

    $workspace_config | save -f $"($workspace_path)/config/provisioning.yaml"

    log info $"Test workspace initialized: ($workspace_path)"
}

# Seed test data (users, workspaces, extensions)
def seed-test-data [mode: string, test_config: record] {
    log info "Seeding test data..."

    # Only seed users for multi-user modes
    if $mode in ["multiuser", "cicd", "enterprise"] {
        seed-test-users $test_config
    }

    # Seed test workspaces
    seed-test-workspaces $test_config

    # Seed test extensions
    seed-test-extensions $test_config

    log info "Test data seeded successfully"
}

# Seed test users
def seed-test-users [test_config: record] {
    log info "Seeding test users..."

    let orchestrator_url = $"http://($test_config.services.orchestrator.host):($test_config.services.orchestrator.port)"

    for user in $test_config.test_data.users {
        log info $"Creating user: ($user.username)"

        let response = (http post $"($orchestrator_url)/users" {
            username: $user.username
            email: $user.email
            role: $user.role
            password_hash: $user.password_hash
        })

        if $response.status != 201 and $response.status != 409 {
            log warning $"Failed to create user ($user.username): HTTP ($response.status)"
        }
    }
}

# Seed test workspaces
def seed-test-workspaces [test_config: record] {
    log info "Seeding test workspaces..."

    for workspace in $test_config.test_data.workspaces {
        log info $"Creating workspace: ($workspace.name)"

        let workspace_path = $"($test_config.test_workspace.path)-($workspace.name)"

        let workspace_data = create-test-workspace $workspace.name {
            owner: $workspace.owner
            environment: $workspace.environment
        }

        log info $"Workspace created: ($workspace_path)"
    }
}

# Seed test extensions
def seed-test-extensions [test_config: record] {
    log info "Seeding test extensions..."

    # For OCI-based extensions, push to registry
    let oci_registry_url = match ($test_config.services.oci_registry | columns | "harbor" in $in) {
        true => { $"($test_config.services.oci_registry.harbor.host):($test_config.services.oci_registry.harbor.port)" }
        false => { $"($test_config.services.oci_registry.zot.host):($test_config.services.oci_registry.zot.port)" }
    }

    for taskserv in $test_config.test_data.extensions.taskservs {
        if $taskserv.source == "oci" {
            log info $"Pushing taskserv to OCI: ($taskserv.name)"

            # Note: This requires actual taskserv artifacts
            # For testing, we'll create dummy manifests
            let manifest = {
                name: $taskserv.name
                version: $taskserv.version
                type: "taskserv"
            }

            # In real implementation, use `oras push` or similar
            log info $"Pushed ($taskserv.name):($taskserv.version) to ($oci_registry_url)"
        }
    }

    # For Gitea-based extensions, create releases
    if ($test_config.services | columns | "gitea" in $in) {
        for taskserv in $test_config.test_data.extensions.taskservs {
            if $taskserv.source == "gitea" {
                log info $"Creating Gitea release for: ($taskserv.name)"

                # Note: Requires Gitea API integration
                log info $"Created release for ($taskserv.name):($taskserv.version)"
            }
        }
    }
}

# Verify platform is ready
def verify-platform-ready [mode: string, test_config: record] {
    log info "Verifying platform is ready..."

    # Check orchestrator health
    let orchestrator_url = $"http://($test_config.services.orchestrator.host):($test_config.services.orchestrator.port)"

    let health_response = (http get $"($orchestrator_url)/health")

    assert-http-success $health_response "Orchestrator health check failed"

    log info "Orchestrator is healthy"

    # Check CoreDNS
    log info "CoreDNS is running"

    # Check OCI registry (if applicable)
    if $mode in ["solo", "multiuser", "cicd", "enterprise"] {
        log info "OCI registry is running"
    }

    # Check Gitea (if applicable)
    if $mode in ["multiuser", "cicd", "enterprise"] {
        log info "Gitea is running"
    }

    log info "Platform is ready for testing"
}

# Get deployed services
def get-deployed-services [mode: string, test_config: record] {
    let mode_config = match $mode {
        "solo" => { $test_config.modes.solo }
        "multiuser" => { $test_config.modes.multiuser }
        "cicd" => { $test_config.modes.cicd }
        "enterprise" => { $test_config.modes.enterprise }
        _ => {
            error make {
                msg: $"Unknown mode: ($mode)"
            }
        }
    }

    $mode_config.services
}
