#!perl
use Cassandane::Tiny;

sub test_emailsubmission_set_futurerelease
    :min_version_3_1 :needs_component_calalarmd
{
    my ($self) = @_;
    my $jmap = $self->{jmap};

    my $res = $jmap->CallMethods( [ [ 'Identity/get', {}, "R1" ] ] );
    my $identityid = $res->[0][1]->{list}[0]->{id};
    $self->assert_not_null($identityid);

    xlog $self, "Generate an email via IMAP";
    $self->make_message("foo", body => "an email\r\nwithCRLF\r\n") or die;

    xlog $self, "get email id";
    $res = $jmap->CallMethods( [ [ 'Email/query', {}, "R1" ] ] );
    my $emailid = $res->[0][1]->{ids}[0];

    xlog $self, "create email submissions";
    $res = $jmap->CallMethods( [ [ 'EmailSubmission/set', {
        create => {
            '1' => {
                identityId => $identityid,
                emailId  => $emailid,
                envelope => {
                    mailFrom => {
                        email => 'from@localhost',
                        parameters => {
                            "holdfor" => "30",
                        }
                    },
                    rcptTo => [{
                        email => 'rcpt1@localhost',
                    }, {
                        email => 'rcpt2@localhost',
                    }],
                },
            },
            '2' => {
                identityId => $identityid,
                emailId  => $emailid,
                envelope => {
                    mailFrom => {
                        email => 'from@localhost',
                        parameters => {
                            "holdfor" => "30",
                        }
                    },
                    rcptTo => [{
                        email => 'rcpt1@localhost',
                    }, {
                        email => 'rcpt2@localhost',
                    }],
                },
            }
       }
    }, "R1" ] ] );
    my $msgsubid1 = $res->[0][1]->{created}{1}{id};
    my $msgsubid2 = $res->[0][1]->{created}{2}{id};
    $self->assert_not_null($msgsubid1);
    $self->assert_not_null($msgsubid2);

    xlog $self, "event were added to the alarmdb";
    my $alarmdata = $self->{instance}->getalarmdb();
    $self->assert_num_equals(2, scalar @$alarmdata);

    $res = $jmap->CallMethods([['EmailSubmission/get', { ids => undef }, "R2"]]);
    $self->assert_num_equals(2, scalar @{$res->[0][1]->{list}});
    $self->assert_deep_equals([], $res->[0][1]->{notFound});
    $self->assert_str_equals('pending', $res->[0][1]->{list}[0]->{undoStatus});
    $self->assert_str_equals('pending', $res->[0][1]->{list}[1]->{undoStatus});
    my $state = $res->[0][1]->{state};

    xlog $self, "cancel first email submission";
    $res = $jmap->CallMethods([
        ['EmailSubmission/set', {
            update => { $msgsubid1 => {
                "undoStatus" => "canceled",
            }},
        }, 'R3'],
    ]);

    $self->assert_not_null($res->[0][1]{updated});
    $self->assert_null($res->[0][1]{notUpdated});

    xlog $self, "one event left in the alarmdb";
    $alarmdata = $self->{instance}->getalarmdb();
    $self->assert_num_equals(1, scalar @$alarmdata);

    $res = $jmap->CallMethods([['EmailSubmission/get', { ids => [ $msgsubid1 ] }, "R4"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{list}});
    $self->assert_deep_equals([], $res->[0][1]->{notFound});
    $self->assert_str_equals('canceled', $res->[0][1]->{list}[0]->{undoStatus});

    xlog $self, "destroy first email submission";
    $res = $jmap->CallMethods([
        ['EmailSubmission/set', {
            destroy => [ $msgsubid1 ]
        }, 'R5'],
    ]);

    $self->assert_not_null($res->[0][1]{destroyed});
    $self->assert_null($res->[0][1]{notDestroyed});

    xlog $self, "one event left in the alarmdb";
    $alarmdata = $self->{instance}->getalarmdb();
    $self->assert_num_equals(1, scalar @$alarmdata);

    $res = $jmap->CallMethods([['EmailSubmission/get', { ids => undef }, "R6"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{list}});
    $self->assert_deep_equals([], $res->[0][1]->{notFound});

    xlog $self, "set up a send block";
    $self->{instance}->set_smtpd({ begin_data => ["451", "4.3.0 [jmapError:forbiddenToSend] try later"] });

    xlog $self, "attempt delivery of the second email";
    my $now = DateTime->now();
    $self->{instance}->run_command({ cyrus => 1 }, 'calalarmd', '-t' => $now->epoch() + 60 );

    xlog $self, "still pending";
    $res = $jmap->CallMethods([['EmailSubmission/get', { ids => [ $msgsubid2 ] }, "R7"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{list}});
    $self->assert_deep_equals([], $res->[0][1]->{notFound});
    $self->assert_str_equals('pending', $res->[0][1]->{list}[0]->{undoStatus});

    xlog $self, "one event left in the alarmdb";
    $alarmdata = $self->{instance}->getalarmdb();
    $self->assert_num_equals(1, scalar @$alarmdata);

    xlog $self, "clear the send block";
    $self->{instance}->set_smtpd();

    xlog $self, "trigger delivery of second email submission";
    $self->{instance}->run_command({ cyrus => 1 }, 'calalarmd', '-t' => $now->epoch() + 600 );

    $res = $jmap->CallMethods([['EmailSubmission/get', { ids => [ $msgsubid2 ] }, "R7"]]);
    $self->assert_num_equals(1, scalar @{$res->[0][1]->{list}});
    $self->assert_deep_equals([], $res->[0][1]->{notFound});
    $self->assert_str_equals('final', $res->[0][1]->{list}[0]->{undoStatus});

    xlog $self, "no events left in the alarmdb";
    $alarmdata = $self->{instance}->getalarmdb();
    $self->assert_num_equals(0, scalar @$alarmdata);

    xlog $self, "attempt to cancel second email submission (should fail)";
    $res = $jmap->CallMethods([
        ['EmailSubmission/set', {
            update => { $msgsubid2 => {
                "undoStatus" => "canceled",
            }},
        }, 'R8'],
    ]);

    $self->assert_null($res->[0][1]{updated});
    $self->assert_not_null($res->[0][1]{notUpdated});
}
