use strict;
use warnings;
use Test::More;
use Time::HiRes qw(time);

# Skip if no server available
my $test_url = $ENV{HYPERSONIC_TEST_URL} || 'http://127.0.0.1:8080/';

# Quick connectivity check
eval {
    require IO::Socket::INET;
    my $sock = IO::Socket::INET->new(
        PeerHost => '127.0.0.1',
        PeerPort => 8080,
        Timeout  => 1,
    );
    die "Cannot connect" unless $sock;
    close($sock);
};
if ($@) {
    plan skip_all => "No test server at $test_url - set HYPERSONIC_TEST_URL or start server";
}

plan tests => 11;

use_ok('Hypersonic::Future');
use_ok('Hypersonic::UA');
use_ok('Hypersonic::Event');

# Compile with async support
ok(Hypersonic::Future->compile, 'Future compiled');
ok(Hypersonic::UA->compile(async => 1), 'UA compiled with async');

my $backend = Hypersonic::Event->best_backend;
ok($backend, "Event backend detected: $backend");

my $ua = bless {}, 'Hypersonic::UA';
ok($ua, 'UA instance created');

# Test 1: Basic async request works
subtest 'basic async request' => sub {
    plan tests => 4;
    
    my $f = $ua->get_async($test_url);
    ok($f, 'get_async returns future');
    isa_ok($f, 'Hypersonic::Future');
    
    my $ticks = 0;
    while ($ua->tick) {
        $ticks++;
    }
    
    ok($f->is_done || $f->is_failed, 'Future completed');
    ok($ticks < 1000, "Completed in $ticks ticks");
};

# Test 2: Connection pooling - second request should be faster
subtest 'connection pooling performance' => sub {
    plan tests => 3;
    
    # First request (may need new connection)
    my $start1 = time();
    my $f1 = $ua->get_async($test_url);
    while ($ua->tick) { }
    my $time1 = time() - $start1;
    ok($f1->is_done, 'First request completed');
    
    # Second request (should use pooled connection)
    my $start2 = time();
    my $f2 = $ua->get_async($test_url);
    while ($ua->tick) { }
    my $time2 = time() - $start2;
    ok($f2->is_done, 'Second request completed');
    
    # Pooled connection should generally be faster (no connect overhead)
    # But we just verify both work - timing can vary
    ok($time1 > 0 && $time2 > 0, "Times: first=${time1}s, second=${time2}s");
};

# Test 3: Concurrent requests
subtest 'concurrent requests' => sub {
    plan tests => 3;
    
    my $concurrency = 10;
    my @futures;
    
    for (1..$concurrency) {
        push @futures, $ua->get_async($test_url);
    }
    
    is(scalar @futures, $concurrency, "Started $concurrency concurrent requests");
    
    my $ticks = 0;
    while ($ua->tick) {
        $ticks++;
    }
    
    my $completed = grep { $_->is_done } @futures;
    ok($completed > 0, "Completed $completed/$concurrency requests");
    ok($ticks < 10000, "Finished in $ticks ticks");
};

# Test 4: Throughput benchmark (small scale)
subtest 'throughput benchmark' => sub {
    plan tests => 2;
    
    my $total = 100;
    my $concurrency = 20;
    
    my $start = time();
    my @futures;
    my $completed = 0;
    my $failed = 0;
    my $ticks = 0;
    
    # Start initial batch
    for (1..$concurrency) {
        push @futures, $ua->get_async($test_url);
    }
    
    while ($completed + $failed < $total && $ticks < 50000) {
        $ua->tick;
        $ticks++;
        
        my @pending;
        for my $f (@futures) {
            if ($f->is_done) {
                $completed++;
                if ($completed + $failed + @pending < $total) {
                    push @pending, $ua->get_async($test_url);
                }
            } elsif ($f->is_failed) {
                $failed++;
                if ($completed + $failed + @pending < $total) {
                    push @pending, $ua->get_async($test_url);
                }
            } else {
                push @pending, $f;
            }
        }
        @futures = @pending;
    }
    
    my $elapsed = time() - $start;
    my $rps = $elapsed > 0 ? $completed / $elapsed : 0;
    
    ok($completed >= $total * 0.9, "Completed $completed/$total requests (failed: $failed)");
    diag(sprintf("Throughput: %.0f req/sec in %.3fs (%d ticks)", $rps, $elapsed, $ticks));
    ok($rps > 100, "Throughput > 100 req/sec (got $rps)");
};
