use strict;
use warnings;
use Test::More tests => 4;
use Google::gRPC::Client;
use Google::gRPC::ChannelPool;
use Google::gRPC::Deadline;
use Google::gRPC::Status;
use Google::gRPC::Framing;

note('=== Demonstrating Google-gRPC Features: Deadlines, Retries, Keepalives, Rich Error Details ===');

subtest '1. Deadlines & Timeout Formatting' => sub {
    my $t1 = Google::gRPC::Deadline::format_grpc_timeout(0.5);
    my $t2 = Google::gRPC::Deadline::format_grpc_timeout(10);
    my $t3 = Google::gRPC::Deadline::format_grpc_timeout(3600);

    is($t1, '500m', 'formatted 0.5 sec to 500m');
    is($t2, '10S', 'formatted 10 sec to 10S');
    is($t3, '1H', 'formatted 3600 sec to 1H');

    my $channel = Google::gRPC::Channel->new(
        target      => 'spanner.googleapis.com:443',
        engine_type => 'PP',
        timeout     => '500m',
    );

    my $stream = $channel->create_stream(
        service => 'google.spanner.v1.Spanner',
        method  => 'ExecuteSql',
        type    => 'unary',
    );

    ok($stream->deadline > 0, 'stream initialized with deadline timestamp');
};

subtest '2. Transparent Retries & Backoff Configuration' => sub {
    my $pool = Google::gRPC::ChannelPool->new(
        target       => 'spanner.googleapis.com:443',
        resolved_ips => ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
        engine_type  => 'PP',
    );

    my $client = Google::gRPC::Client->new(
        channel_pool        => $pool,
        max_retries         => 3,
        initial_backoff_sec => 0.05,
        max_backoff_sec     => 0.5,
        backoff_factor      => 2.0,
    );

    is($client->max_retries, 3, 'max_retries configured to 3');
    is($client->initial_backoff_sec, 0.05, 'initial backoff configured');
    is($client->backoff_factor, 2.0, 'backoff factor configured');
};

subtest '3. HTTP/2 PING Keepalives' => sub {
    my $channel = Google::gRPC::Channel->new(
        target               => 'spanner.googleapis.com:443',
        engine_type          => 'PP',
        keepalive_time_sec   => 30,
        keepalive_timeout_sec => 10,
    );

    is($channel->keepalive_time_sec, 30, 'keepalive time sec set');
    is($channel->keepalive_timeout_sec, 10, 'keepalive timeout sec set');

    $channel->last_activity_time(time() - 35);
    my $ping_fired = 0;
    $channel->send_ping(sub { $ping_fired = 1; });

    my $output = $channel->get_output();
    ok(length($output) > 0, 'emitted HTTP/2 PING frame on idle channel');
};

subtest '4. Rich Error Details (grpc-status-details-bin)' => sub {
    my $status_proto = {
        code    => 3,
        message => 'INVALID_ARGUMENT: Query syntax error at line 1, column 15',
        details => [
            { type_url => 'type.googleapis.com/google.rpc.BadRequest', value => 'field_violations_payload' }
        ]
    };

    my $dynamic = Google::ProtocolBuffers::Dynamic->new;
    $dynamic->load_string('demo_status.proto', <<'EOF');
syntax = "proto3";
package google.rpc;

message Status {
  int32 code = 1;
  string message = 2;
  repeated Any details = 3;
}

message Any {
  string type_url = 1;
  bytes value = 2;
}
EOF
    $dynamic->map_package('google.rpc', 'Google::DemoRpc');
    $dynamic->resolve_references();

    my $encoded_bin = Google::DemoRpc::Status->encode($status_proto);

    my $status_obj = Google::gRPC::Status->parse_status_details($encoded_bin);

    is($status_obj->code, 3, 'status code matches 3');
    like($status_obj->message, qr/Query syntax error/, 'status message parsed');
    is(scalar(@{$status_obj->details}), 1, 'details array parsed');
    is($status_obj->details->[0]->{type_url}, 'type.googleapis.com/google.rpc.BadRequest', 'type_url matches');
};

done_testing();
