#!perl
use Cassandane::Tiny;

sub test_email_query_negative_position
    :min_version_3_5 :needs_component_sieve :needs_component_jmap
    :JMAPQueryCacheMaxAge1s :JMAPExtensions
{
    my ($self) = @_;
    my $jmap = $self->{jmap};

    xlog "Creating emails";
    foreach my $i (1..9) {
        $self->make_message("test") || die;
    }

    xlog $self, "run squatter";
    $self->{instance}->run_command({cyrus => 1}, 'squatter');

    xlog "Query emails";
    my $res = $jmap->CallMethods([
        ['Email/query', {
            sort => [{ property => 'id' }],
        }, 'R1'],
    ]);
    my @emailIds = @{$res->[0][1]{ids}};
    $self->assert_num_equals(9, scalar @emailIds);

    my $using = [
        'https://cyrusimap.org/ns/jmap/performance',
        'https://cyrusimap.org/ns/jmap/debug',
        'urn:ietf:params:jmap:core',
        'urn:ietf:params:jmap:mail',
    ];

    xlog "Query with negative position (in range)";
    $res = $jmap->CallMethods([
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -3,
            limit => 2,
            disableGuidSearch => JSON::true,
        }, 'R1'],
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -3,
            limit => 2,
            disableGuidSearch => JSON::true,
        }, 'R2'],
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -3,
            limit => 2,
            disableGuidSearch => JSON::false,
        }, 'R3'],
    ], $using);
    my @wantIds = @emailIds[6..7];
    # Check UID search
    $self->assert_equals(JSON::false, $res->[0][1]{performance}{details}{isGuidSearch});
    $self->assert_equals(JSON::false, $res->[0][1]{performance}{details}{isCached});
    $self->assert_num_equals(6, $res->[0][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[0][1]{ids});
    $self->assert_equals(JSON::false, $res->[1][1]{performance}{details}{isGuidSearch});

    $self->assert_equals(JSON::true, $res->[1][1]{performance}{details}{isCached});
    $self->assert_num_equals(6, $res->[1][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[1][1]{ids});
    # Check GUID search
    $self->assert_equals(JSON::true, $res->[2][1]{performance}{details}{isGuidSearch});
    $self->assert_num_equals(6, $res->[2][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[2][1]{ids});

    xlog "Create dummy message to invalidate query cache";
    $self->make_message("dummy") || die;

    xlog "Query with negative position (out of range)";
    $res = $jmap->CallMethods([
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -100,
            limit => 2,
            disableGuidSearch => JSON::true,
        }, 'R1'],
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -100,
            limit => 2,
            disableGuidSearch => JSON::true,
        }, 'R2'],
        ['Email/query', {
            filter => { subject => 'test' },
            sort => [{ property => 'id' }],
            position => -100,
            limit => 2,
            disableGuidSearch => JSON::false,
        }, 'R3'],
    ], $using);
    @wantIds = @emailIds[0..1];
    # Check UID search
    $self->assert_equals(JSON::false, $res->[0][1]{performance}{details}{isGuidSearch});
    $self->assert_equals(JSON::false, $res->[0][1]{performance}{details}{isCached});
    $self->assert_num_equals(0, $res->[0][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[0][1]{ids});
    $self->assert_equals(JSON::false, $res->[1][1]{performance}{details}{isGuidSearch});
    $self->assert_equals(JSON::true, $res->[1][1]{performance}{details}{isCached});
    $self->assert_num_equals(0, $res->[1][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[1][1]{ids});
    # Check GUID search
    $self->assert_equals(JSON::true, $res->[2][1]{performance}{details}{isGuidSearch});
    $self->assert_num_equals(0, $res->[2][1]{position});
    $self->assert_deep_equals(\@wantIds, $res->[2][1]{ids});
}
