#!perl
use Cassandane::Tiny;

sub test_addressbook_set_state
    :min_version_3_9 :needs_component_jmap :needs_dependency_icalvcard
{
    my ($self) = @_;

    my $jmap = $self->{jmap};

    xlog $self, "create with invalid state token";
    my $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => "badstate",
                    create => { "1" => { name => "foo" }}
                }, "R1"]
        ]);
    $self->assert_str_equals('error', $res->[0][0]);
    $self->assert_str_equals('stateMismatch', $res->[0][1]{type});

    xlog $self, "create with wrong state token";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => "987654321",
                    create => { "1" => { name => "foo" }}
                }, "R1"]
        ]);
    $self->assert_str_equals('error', $res->[0][0]);
    $self->assert_str_equals('stateMismatch', $res->[0][1]{type});

    xlog $self, "create addressbook";
    $res = $jmap->CallMethods([
            ['AddressBook/set', { create => { "1" => {
                            name => "foo"
             }}}, "R1"]
    ]);
    $self->assert_not_null($res);

    my $id = $res->[0][1]{created}{"1"}{id};
    my $state = $res->[0][1]{newState};

    xlog $self, "update addressbook $id with current state";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => $state,
                    update => {"$id" => {name => "bar"}}
            }, "R1"]
    ]);
    $self->assert_not_null($res->[0][1]{newState});
    $self->assert_str_not_equals($state, $res->[0][1]{newState});

    my $oldState = $state;
    $state = $res->[0][1]{newState};

    xlog $self, "setAddressBook noops must keep state";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {}, "R1"],
            ['AddressBook/set', {}, "R2"],
            ['AddressBook/set', {}, "R3"]
    ]);
    $self->assert_not_null($res->[0][1]{newState});
    $self->assert_str_equals($state, $res->[0][1]{newState});

    xlog $self, "update addressbook $id with expired state";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => $oldState,
                    update => {"$id" => {name => "baz"}}
            }, "R1"]
    ]);
    $self->assert_str_equals('error', $res->[0][0]);
    $self->assert_str_equals("stateMismatch", $res->[0][1]{type});
    $self->assert_str_equals('R1', $res->[0][2]);

    xlog $self, "get addressbook $id to make sure state didn't change";
    $res = $jmap->CallMethods([['AddressBook/get', {ids => [$id]}, "R1"]]);
    $self->assert_str_equals($state, $res->[0][1]{state});
    $self->assert_str_equals('bar', $res->[0][1]{list}[0]{name});

    xlog $self, "destroy addressbook $id with expired state";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => $oldState,
                    destroy => [$id]
            }, "R1"]
    ]);
    $self->assert_str_equals('error', $res->[0][0]);
    $self->assert_str_equals("stateMismatch", $res->[0][1]{type});
    $self->assert_str_equals('R1', $res->[0][2]);

    xlog $self, "destroy addressbook $id with current state";
    $res = $jmap->CallMethods([
            ['AddressBook/set', {
                    ifInState => $state,
                    destroy => [$id]
            }, "R1"]
    ]);
    $self->assert_str_not_equals($state, $res->[0][1]{newState});
    $self->assert_str_equals($id, $res->[0][1]{destroyed}[0]);
}
