# Solo Mode Integration Tests
# Comprehensive tests for solo mode deployment

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

# Main test suite
export def main [] {
    log info "Running Solo Mode Integration Tests"

    let test_config = (load-test-config)

    # Setup solo mode environment
    log info "Setting up solo mode environment..."
    setup-solo-mode $test_config

    mut results = []

    # Run all solo mode tests
    $results = ($results | append (test-minimal-services $test_config))
    $results = ($results | append (test-single-user-operations $test_config))
    $results = ($results | append (test-no-multiuser-services $test_config))
    $results = ($results | append (test-workspace-creation $test_config))
    $results = ($results | append (test-server-deployment-with-dns $test_config))
    $results = ($results | append (test-taskserv-installation $test_config))
    $results = ($results | append (test-extension-loading-from-oci $test_config))
    $results = ($results | append (test-admin-permissions $test_config))

    # Teardown
    log info "Tearing down solo mode environment..."
    teardown-solo-mode $test_config

    # Report results
    report-test-results $results
}

# Setup solo mode environment
def setup-solo-mode [test_config: record] {
    # Deploy solo mode services
    nu provisioning/tests/integration/setup_test_environment.nu --mode solo
}

# Teardown solo mode environment
def teardown-solo-mode [test_config: record] {
    nu provisioning/tests/integration/teardown_test_environment.nu --force
}

# Test 1: Verify minimal services running
def test-minimal-services [test_config: record] {
    run-test "solo-mode-minimal-services" {
        log info "Testing minimal services in solo mode..."

        # Verify orchestrator is running
        assert-true (check-service-health "orchestrator") "Orchestrator should be running"

        # Verify CoreDNS is running
        assert-true (check-service-health "coredns") "CoreDNS should be running"

        # Verify OCI registry (Zot) is running
        let oci_url = $"http://($test_config.services.oci_registry.zot.host):($test_config.services.oci_registry.zot.port)/v2/"

        let response = (http get $oci_url)
        assert-http-success $response "OCI registry should be running"

        # Verify multi-user services are NOT running
        assert-false (check-service-health "gitea") "Gitea should NOT be running in solo mode"
        assert-false (check-service-health "postgres") "PostgreSQL should NOT be running in solo mode"

        log info "✓ Minimal services verified"
    }
}

# Test 2: Single user operations
def test-single-user-operations [test_config: record] {
    run-test "solo-mode-single-user" {
        log info "Testing single user operations..."

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

        # All operations should work as admin user (no authentication required)
        let response = (http get $"($orchestrator_url)/tasks")

        assert-http-success $response "Task list should be accessible"

        log info "✓ Single user operations work"
    }
}

# Test 3: Verify no multi-user services
def test-no-multiuser-services [test_config: record] {
    run-test "solo-mode-no-multiuser-services" {
        log info "Testing that multi-user services are absent..."

        # Attempt to connect to Gitea (should fail)
        let gitea_url = $"http://($test_config.services.gitea.host):($test_config.services.gitea.port)"

        let gitea_result = (do {
            http get $gitea_url
        } | complete)

        if $gitea_result.exit_code == 0 {
            error make { msg: "Gitea should not be accessible in solo mode" }
        } else {
            # Expected to fail
            log info "✓ Gitea is not running (expected)"
        }

        # Attempt to connect to PostgreSQL (should fail)
        let postgres_result = (do {
            psql -h $test_config.services.postgres.host -p $test_config.services.postgres.port -U test -d test -c "SELECT 1"
        } | complete)

        if $postgres_result.exit_code == 0 {
            error make { msg: "PostgreSQL should not be accessible in solo mode" }
        } else {
            # Expected to fail
            log info "✓ PostgreSQL is not running (expected)"
        }

        log info "✓ Multi-user services are absent"
    }
}

# Test 4: Create workspace in solo mode
def test-workspace-creation [test_config: record] {
    run-test "solo-mode-create-workspace" {
        log info "Testing workspace creation in solo mode..."

        let workspace = create-test-workspace "solo-test-ws" {
            provider: "local"
            environment: "test"
        }

        # Verify workspace directory structure
        assert-true ($"($workspace.path)/config" | path exists) "Config directory should exist"
        assert-true ($"($workspace.path)/infra" | path exists) "Infra directory should exist"
        assert-true ($"($workspace.path)/extensions" | path exists) "Extensions directory should exist"
        assert-true ($"($workspace.path)/runtime" | path exists) "Runtime directory should exist"

        # Verify workspace config
        let config = (open $"($workspace.path)/config/provisioning.yaml")
        assert-eq $config.workspace.name "solo-test-ws" "Workspace name should match"

        # Cleanup
        cleanup-test-workspace $workspace

        log info "✓ Workspace created successfully"
    }
}

# Test 5: Deploy server with auto-DNS registration
def test-server-deployment-with-dns [test_config: record] {
    run-test "solo-mode-server-with-dns" {
        log info "Testing server deployment with DNS registration..."

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

        # Create server
        let server_name = "test-server-01"

        let create_response = (http post $"($orchestrator_url)/workflows/servers/create" {
            server: {
                hostname: $server_name
                provider: "local"
                cores: 2
                memory: 4096
                zone: "local"
            }
            check: true
        })

        assert-http-success $create_response "Server creation should succeed"

        let task_id = $create_response.body.task_id

        # Wait for server creation to complete
        wait-for-condition --timeout 120 --interval 5 {
            let status_response = (http get $"($orchestrator_url)/tasks/($task_id)")
            $status_response.body.status == "completed"
        } "server creation to complete"

        # Verify DNS registration
        let dns_query = (dig @$test_config.services.coredns.host $"($server_name).local" +short)

        assert-not-empty $dns_query "DNS record should exist for server"

        log info $"✓ Server created with DNS: ($server_name).local → ($dns_query)"

        # Cleanup server
        delete-test-server $task_id
    }
}

# Test 6: Install taskserv (kubernetes)
def test-taskserv-installation [test_config: record] {
    run-test "solo-mode-taskserv-installation" {
        log info "Testing taskserv installation..."

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

        # First, create a server
        let server_response = (http post $"($orchestrator_url)/workflows/servers/create" {
            server: {
                hostname: "taskserv-test"
                provider: "local"
                cores: 4
                memory: 8192
            }
            check: true
        })

        let server_task_id = $server_response.body.task_id

        # Wait for server creation
        wait-for-condition --timeout 120 {
            let status = (http get $"($orchestrator_url)/tasks/($server_task_id)")
            $status.body.status == "completed"
        } "server creation"

        # Install kubernetes taskserv
        let taskserv_response = (http post $"($orchestrator_url)/workflows/taskserv/create" {
            taskserv: "kubernetes"
            server: "taskserv-test"
            check: true
        })

        assert-http-success $taskserv_response "Taskserv installation should succeed"

        let taskserv_task_id = $taskserv_response.body.task_id

        # Wait for taskserv installation
        wait-for-condition --timeout 300 {
            let status = (http get $"($orchestrator_url)/tasks/($taskserv_task_id)")
            $status.body.status == "completed"
        } "taskserv installation"

        log info "✓ Taskserv installed successfully"

        # Cleanup
        delete-test-server $server_task_id
    }
}

# Test 7: Extension loading from local OCI
def test-extension-loading-from-oci [test_config: record] {
    run-test "solo-mode-extension-loading-oci" {
        log info "Testing extension loading from OCI registry..."

        let oci_url = $"http://($test_config.services.oci_registry.zot.host):($test_config.services.oci_registry.zot.port)"

        # Push a test extension to OCI
        # Note: In real implementation, this would use `oras push`
        # For testing, we'll verify OCI registry is accessible

        let catalog_response = (http get $"($oci_url)/v2/_catalog")

        assert-http-success $catalog_response "OCI catalog should be accessible"

        log info "✓ OCI registry accessible for extension loading"
    }
}

# Test 8: Admin permissions (all operations allowed)
def test-admin-permissions [test_config: record] {
    run-test "solo-mode-admin-permissions" {
        log info "Testing admin permissions in solo mode..."

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

        # In solo mode, all operations are allowed (single admin user)

        # Test: List tasks
        let tasks_response = (http get $"($orchestrator_url)/tasks")
        assert-http-success $tasks_response "Admin can list tasks"

        # Test: List servers
        let servers_response = (http get $"($orchestrator_url)/servers")
        assert-http-success $servers_response "Admin can list servers"

        # Test: Create workflow
        let workflow_response = (http post $"($orchestrator_url)/workflows/servers/create" {
            server: {
                hostname: "admin-test"
                provider: "local"
            }
            check: true
        })
        assert-http-success $workflow_response "Admin can create workflows"

        log info "✓ Admin has full permissions in solo mode"
    }
}

# Report test results
def report-test-results [results: list] {
    let total = ($results | length)
    let passed = ($results | where status == "passed" | length)
    let failed = ($results | where status == "failed" | length)

    log info "========================================="
    log info "Solo Mode Test Results"
    log info "========================================="
    log info $"Total:  ($total)"
    log info $"Passed: ($passed)"
    log info $"Failed: ($failed)"
    log info "========================================="

    if $failed > 0 {
        log error "Some tests failed:"
        $results | where status == "failed" | each { |test|
            log error $"  - ($test.test_name): ($test.error_message)"
        }
    }

    $results
}
