#!perl
use Cassandane::Tiny;

sub test_mailbox_query_filteroperator
    :min_version_3_1 :NoAltNameSpace
{
    my ($self) = @_;

    my $jmap = $self->{jmap};
    my $imaptalk = $self->{store}->get_client();

    xlog $self, "create mailbox tree";
    $imaptalk->create("INBOX.Ham") || die;
    $imaptalk->create("INBOX.Spam", "(USE (\\Junk))") || die;
    $imaptalk->create("INBOX.Ham.Zonk") || die;
    $imaptalk->create("INBOX.Ham.Bonk") || die;

    xlog $self, "(re)fetch mailboxes";
    my $res = $jmap->CallMethods([['Mailbox/get', { properties => ["name"] }, 'R1' ]]);
    $self->assert_num_equals(5, scalar @{$res->[0][1]{list}});
    my %mboxids = map { $_->{name} => $_->{id} } @{$res->[0][1]{list}};
    $self->assert(exists $mboxids{'Inbox'});

    xlog $self, "Subscribe mailbox Ham";
    $res = $jmap->CallMethods([
        ['Mailbox/set', {
            update => {
                $mboxids{'Ham'} => {
                    isSubscribed => JSON::true,
                },
            },
        }, 'R1']
    ]);
    $self->assert(exists $res->[0][1]{updated}{$mboxids{'Ham'}});

    xlog $self, "make sure subscribing changed state";
    $self->assert_not_equals($res->[0][1]{oldState}, $res->[0][1]{newState});

    my $state = $res->[0][1]{oldState};
    $res = $jmap->CallMethods([['Mailbox/changes', { sinceState => $state }, "R1"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]{updated}});
    $self->assert_equals($res->[0][1]{updated}[0], $mboxids{'Ham'});
    $self->assert_null($res->[0][1]{updatedProperties});

    xlog $self, "list mailboxes filtered by parentId OR role";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            operator => "OR",
            conditions => [{
                parentId => $mboxids{'Ham'},
            }, {
                hasAnyRole => JSON::true,
            }],
        },
        sort => [{ property => "name" }],
    }, "R1"]]);
    $self->assert_num_equals(4, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Bonk'}, $res->[0][1]{ids}[0]);
    $self->assert_str_equals($mboxids{'Inbox'}, $res->[0][1]{ids}[1]);
    $self->assert_str_equals($mboxids{'Spam'}, $res->[0][1]{ids}[2]);
    $self->assert_str_equals($mboxids{'Zonk'}, $res->[0][1]{ids}[3]);

    xlog $self, "list mailboxes filtered by name";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            name => 'Zonk',
        },
    }, "R1"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Zonk'}, $res->[0][1]{ids}[0]);

    xlog $self, "list mailboxes filtered by isSubscribed";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            isSubscribed => JSON::true,
        },
        sort => [{ property => "name" }],
    }, "R1"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Ham'}, $res->[0][1]{ids}[0]);

    xlog $self, "list mailboxes filtered by isSubscribed is false";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            isSubscribed => JSON::false,
        },
        sort => [{ property => "name" }],
    }, "R1"]]);
    $self->assert_num_equals(4, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Bonk'}, $res->[0][1]{ids}[0]);
    $self->assert_str_equals($mboxids{'Inbox'}, $res->[0][1]{ids}[1]);
    $self->assert_str_equals($mboxids{'Spam'}, $res->[0][1]{ids}[2]);
    $self->assert_str_equals($mboxids{'Zonk'}, $res->[0][1]{ids}[3]);

    xlog $self, "list mailboxes filtered by parentId AND hasAnyRole false";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            operator => "AND",
            conditions => [{
                parentId => JSON::null,
            }, {
                hasAnyRole => JSON::false,
            }],
        },
        sort => [{ property => "name" }],
    }, "R1"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Ham'}, $res->[0][1]{ids}[0]);

    xlog $self, "list mailboxes filtered by NOT (parentId AND role)";
    $res = $jmap->CallMethods([['Mailbox/query', {
        filter => {
            operator => "NOT",
            conditions => [{
                operator => "AND",
                conditions => [{
                    parentId => JSON::null,
                }, {
                    hasAnyRole => JSON::true,
                }],
            }],
        },
        sort => [{ property => "name" }],
    }, "R1"]]);
    $self->assert_num_equals(3, scalar @{$res->[0][1]->{ids}});
    $self->assert_str_equals($mboxids{'Bonk'}, $res->[0][1]{ids}[0]);
    $self->assert_str_equals($mboxids{'Ham'}, $res->[0][1]{ids}[1]);
    $self->assert_str_equals($mboxids{'Zonk'}, $res->[0][1]{ids}[2]);
}
