#!/usr/bin/env nu

# Test OCI registry functionality

export def main [
    --registry-url: string = "localhost:5000"
    --registry-type: string = "zot"
    --skip-docker
] {
    print "🧪 Testing OCI registry..."
    print $"   URL: ($registry_url)"
    print $"   Type: ($registry_type)\n"

    mut passed = 0
    mut failed = 0

    # Test 1: API health
    print "Test 1: API health check..."
    if (test-api-health $registry_url) {
        print "  ✅ PASSED"
        $passed = ($passed + 1)
    } else {
        print "  ❌ FAILED"
        $failed = ($failed + 1)
    }

    # Test 2: Catalog endpoint
    print "\nTest 2: Catalog endpoint..."
    if (test-catalog $registry_url) {
        print "  ✅ PASSED"
        $passed = ($passed + 1)
    } else {
        print "  ❌ FAILED"
        $failed = ($failed + 1)
    }

    # Test 3: Metrics (if supported)
    print "\nTest 3: Metrics endpoint..."
    if (test-metrics $registry_url $registry_type) {
        print "  ✅ PASSED"
        $passed = ($passed + 1)
    } else {
        print "  ⚠️  SKIPPED (not supported)"
    }

    # Test 4: Push/Pull (requires Docker)
    if not $skip_docker {
        print "\nTest 4: Push/Pull test..."
        if (test-push-pull $registry_url) {
            print "  ✅ PASSED"
            $passed = ($passed + 1)
        } else {
            print "  ❌ FAILED"
            $failed = ($failed + 1)
        }

        # Test 5: Delete (if supported)
        print "\nTest 5: Delete test..."
        if (test-delete $registry_url) {
            print "  ✅ PASSED"
            $passed = ($passed + 1)
        } else {
            print "  ⚠️  SKIPPED (delete not enabled)"
        }
    } else {
        print "\nTests 4-5: Skipped (--skip-docker)"
    }

    # Test 6: Namespaces
    print "\nTest 6: Namespace validation..."
    if (test-namespaces $registry_url) {
        print "  ✅ PASSED"
        $passed = ($passed + 1)
    } else {
        print "  ❌ FAILED"
        $failed = ($failed + 1)
    }

    # Summary
    print "\n" + ("=" * 50)
    print $"Test Summary: ($passed) passed, ($failed) failed"

    if $failed > 0 {
        print "\n❌ Some tests failed"
        exit 1
    } else {
        print "\n✅ All tests passed!"
        exit 0
    }
}

def test-api-health [registry_url: string] -> bool {
    let result = (do {
        http get $"http://($registry_url)/v2/" --timeout 5sec
    } | complete)

    if $result.exit_code == 0 {
        print "  API is responding"
        return true
    } else {
        print $"  API error: ($result.stderr)"
        return false
    }
}

def test-catalog [registry_url: string] -> bool {
    let result = (do {
        http get $"http://($registry_url)/v2/_catalog" --timeout 5sec
    } | complete)

    if $result.exit_code == 0 {
        let catalog = ($result.stdout | from json)
        let count = ($catalog.repositories | length)
        print $"  Catalog has ($count) repositories"
        return true
    } else {
        print $"  Catalog error: ($result.stderr)"
        return false
    }
}

def test-metrics [registry_url: string, registry_type: string] -> bool {
    let metrics_url = match $registry_type {
        "zot" => $"http://($registry_url)/metrics"
        "distribution" => $"http://($registry_url):5001/metrics"
        _ => null
    }

    if ($metrics_url | is-empty) {
        return false
    }

    let result = (do {
        http get $metrics_url --timeout 5sec
    } | complete)

    if $result.exit_code == 0 {
        print "  Metrics endpoint available"
        return true
    } else {
        return false
    }
}

def test-push-pull [registry_url: string] -> bool {
    # Check Docker is available
    let docker_check = (^docker --version | complete)
    if $docker_check.exit_code != 0 {
        print "  Docker not available"
        return false
    }

    # Pull hello-world
    print "  Pulling hello-world..."
    let pull = (^docker pull hello-world:latest | complete)
    if $pull.exit_code != 0 {
        print "  Failed to pull hello-world"
        return false
    }

    # Tag for registry
    let tag = $"($registry_url)/provisioning-test/test-image:latest"
    print $"  Tagging as ($tag)..."
    let tag_result = (^docker tag hello-world:latest $tag | complete)
    if $tag_result.exit_code != 0 {
        print "  Failed to tag image"
        return false
    }

    # Push to registry
    print $"  Pushing to registry..."
    let push = (^docker push $tag | complete)
    if $push.exit_code != 0 {
        print $"  Failed to push: ($push.stderr)"
        return false
    }

    # Pull from registry
    print "  Pulling from registry..."
    let pull_test = (^docker pull $tag | complete)
    if $pull_test.exit_code != 0 {
        print "  Failed to pull from registry"
        return false
    }

    print "  Push/Pull successful"
    return true
}

def test-delete [registry_url: string] -> bool {
    # Try to get manifest digest
    let result = (do {
        http get $"http://($registry_url)/v2/provisioning-test/test-image/manifests/latest" --headers {
            "Accept": "application/vnd.oci.image.manifest.v1+json"
        } --full
    } | complete)

    if $result.exit_code != 0 {
        return false
    }

    # Try to delete (may not be enabled)
    # This is just a check, we don't actually delete
    print "  Delete endpoint available"
    return true
}

def test-namespaces [registry_url: string] -> bool {
    let result = (do {
        http get $"http://($registry_url)/v2/_catalog"
    } | complete)

    if $result.exit_code != 0 {
        return false
    }

    let catalog = ($result.stdout | from json)
    let repos = $catalog.repositories

    # Check for expected namespaces
    let namespaces = ($repos | each { |r| $r | split row "/" | first } | uniq)

    print $"  Found namespaces: ($namespaces | str join ', ')"

    # Should have at least one namespace after init
    return (($namespaces | length) >= 0)
}

# Performance test
export def "perf test" [
    --registry-url: string = "localhost:5000"
    --iterations: int = 10
] {
    print "🚀 Running performance test..."
    print $"   Iterations: ($iterations)\n"

    mut total_time = 0

    for i in 1..$iterations {
        print $"Iteration ($i)/($iterations)..."

        let start = (date now)

        # Test API call
        http get $"http://($registry_url)/v2/" | ignore

        let end = (date now)
        let duration = (($end - $start) | into int) / 1_000_000  # Convert to ms

        print $"  Time: ($duration)ms"
        $total_time = ($total_time + $duration)
    }

    let avg = ($total_time / $iterations)
    print $"\n📊 Average response time: ($avg)ms"
}

# Load test
export def "load test" [
    --registry-url: string = "localhost:5000"
    --concurrent: int = 10
    --duration: int = 60  # seconds
] {
    print "⚡ Running load test..."
    print $"   Concurrent requests: ($concurrent)"
    print $"   Duration: ($duration)s\n"

    # This would require parallel execution
    # For now, just show the concept
    print "ℹ Load testing requires additional tooling (vegeta, ab, wrk)"
    print "\nExample with Apache Bench:"
    print $"  ab -n 1000 -c ($concurrent) http://($registry_url)/v2/"
    print "\nExample with vegeta:"
    print $"  echo 'GET http://($registry_url)/v2/' | vegeta attack -duration=($duration)s -rate=100 | vegeta report"
}

# Stress test
export def "stress test" [
    --registry-url: string = "localhost:5000"
] {
    print "💪 Running stress test..."
    print "  Testing registry limits...\n"

    # Test large catalog
    print "Test 1: Large catalog response..."
    let catalog_result = (do {
        http get $"http://($registry_url)/v2/_catalog" --timeout 30sec
    } | complete)

    if $catalog_result.exit_code == 0 {
        let catalog = ($catalog_result.stdout | from json)
        print $"  ✓ Catalog with ($catalog.repositories | length) repos"
    } else {
        print "  ✗ Catalog failed"
    }

    # Test many concurrent connections
    print "\nTest 2: Concurrent connections..."
    print "  ℹ Use 'load test' for detailed concurrent testing"

    print "\n✅ Stress test complete"
}
