#!perl
use Cassandane::Tiny;

sub test_restore_notes
    :min_version_3_5
{
    my ($self) = @_;

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

    # force creation of notes mailbox prior to creating notes
    my $res = $jmap->CallMethods([
        ['Note/set', {
         }, "R0"]
    ]);

    xlog "create notes";
    $res = $jmap->CallMethods([['Note/set', {create => {
                        "a" => {title => "a"},
                        "b" => {title => "b"},
                        "c" => {title => "c"}
                    }}, "R1"]]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/set', $res->[0][0]);
    $self->assert_str_equals('R1', $res->[0][2]);
    my $noteA = $res->[0][1]{created}{"a"}{id};
    my $noteB = $res->[0][1]{created}{"b"}{id};
    my $noteC = $res->[0][1]{created}{"c"}{id};

    xlog "destroy note C";
    $res = $jmap->CallMethods([['Note/set', {
                    destroy => [$noteC]
                }, "R1.5"]]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/set', $res->[0][0]);
    $self->assert_str_equals('R1.5', $res->[0][2]);

    my $mark = time();
    sleep 2;

    xlog "destroy note A, update note B, create note D";
    $res = $jmap->CallMethods([['Note/set', {
                    destroy => [$noteA],
                    update => {$noteB => {title => "B"}},
                    create => {"d" => {title => "d"}}
                }, "R2"]]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/set', $res->[0][0]);
    $self->assert_str_equals('R2', $res->[0][2]);
    my $noteD = $res->[0][1]{created}{"d"}{id};

    xlog "destroy note D, create note E";
    $res = $jmap->CallMethods([['Note/set', {
                    destroy => [$noteD],
                    create => {
                        "e" => {title => "e"}
                    }
                }, "R4"]]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/set', $res->[0][0]);
    $self->assert_str_equals('R4', $res->[0][2]);
    my $noteE = $res->[0][1]{created}{"e"}{id};
    my $state = $res->[0][1]{newState};

    my $diff = time() - $mark;
    my $period = "PT" . $diff . "S";

    xlog "restore notes prior to most recent changes";
    $res = $jmap->CallMethods([['Backup/restoreNotes', {
                    undoPeriod => $period,
                    undoAll => JSON::false
                }, "R5"]]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Backup/restoreNotes', $res->[0][0]);
    $self->assert_str_equals('R5', $res->[0][2]);
    $self->assert_num_equals(0, $res->[0][1]{numCreatesUndone});
    $self->assert_num_equals(0, $res->[0][1]{numUpdatesUndone});
    $self->assert_num_equals(2, $res->[0][1]{numDestroysUndone});

    xlog "get restored notes";
    $res = $jmap->CallMethods([
        ['Note/get', {
            properties => ['title', 'isFlagged'],
         }, "R6"]
    ]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/get', $res->[0][0]);
    $self->assert_str_equals('R6', $res->[0][2]);

    my @got = sort { $a->{title} cmp $b->{title} } @{$res->[0][1]{list}};
    $self->assert_num_equals(4, scalar @got);
    $self->assert_str_equals('B', $got[0]{title});
    $self->assert_str_equals('a', $got[1]{title});
    $self->assert_str_equals('d', $got[2]{title});
    $self->assert_str_equals('e', $got[3]{title});

    xlog "get note updates";
    $res = $jmap->CallMethods([
        ['Note/changes', {
            sinceState => $state
         }, "R8.5"]
    ]);
    $self->assert_not_null($res);
    $self->assert_str_equals('Note/changes', $res->[0][0]);
    $self->assert_str_equals('R8.5', $res->[0][2]);
    $self->assert_str_equals($state, $res->[0][1]{oldState});
    $self->assert_str_not_equals($state, $res->[0][1]{newState});
    $self->assert_equals(JSON::false, $res->[0][1]{hasMoreChanges});
    $self->assert_num_equals(2, scalar @{$res->[0][1]{created}});
    $self->assert_num_equals(0, scalar @{$res->[0][1]{updated}});
    $self->assert_num_equals(0, scalar @{$res->[0][1]{destroyed}});

    my %noteIds = map { $_ => 1 } @{$res->[0][1]{created}};
    $self->assert_not_null($noteIds{$noteA});
    $self->assert_not_null($noteIds{$noteD});
}
