#!perl
use Cassandane::Tiny;

sub test_calendarevent_participantreply_simple
    :min_version_3_7 :needs_component_jmap :NoStartInstances
{
    my ($self) = @_;

    my $instance = $self->{instance};
    $instance->{config}->set(defaultdomain => 'internal');
    $instance->{config}->set(calendar_user_address_set => 'internal');

    $self->_start_instances();
    $self->_setup_http_service_objects();

    my $jmap = $self->{jmap};
    $jmap->DefaultUsing([
        'urn:ietf:params:jmap:core',
        'urn:ietf:params:jmap:calendars',
        'urn:ietf:params:jmap:principals',
        'urn:ietf:params:jmap:calendars:preferences',
        'https://cyrusimap.org/ns/jmap/calendars',
        'https://cyrusimap.org/ns/jmap/debug',
    ]);

    my $participants = {
        "org" => {
            "name" => "Cassandane",
            roles => {
                'owner' => JSON::true,
            },
            sendTo => {
                imip => 'cassandane@example.com',
            },
        },
        "att1" => {
            "name" => "Bugs Bunny",
            roles => {
                'attendee' => JSON::true,
            },
            sendTo => {
                imip => 'bugs@looneytunes.com',
            },
        },
        "att2" => {
            "name" => "Road Runner",
            roles => {
                'attendee' => JSON::true,
            },
            sendTo => {
                imip => 'rr@looneytunes.com',
            },
        },
    };

    # clean notification cache
    $self->{instance}->getnotify();

    xlog $self, "create scheduled event";
    my $res = $jmap->CallMethods([['CalendarEvent/set', { create => {
                        "1" => {
                            calendarIds => {
                                Default => JSON::true,
                            },
                            "sequence" => 1,
                            "title" => "foo",
                            "description" => "foo's description",
                            "freeBusyStatus" => "busy",
                            "showWithoutTime" => JSON::false,
                            "start" => "2022-11-23T16:45:00",
                            "recurrenceRules" => [{
                                "\@type" => "RecurrenceRule",
                                "frequency" => "weekly"
                            }],
                            "timeZone" => "Australia/Melbourne",
                            "duration" => "PT1H",
                            "replyTo" => { imip => "mailto:cassandane\@example.com"},
                            "participants" => $participants,
                            "recurrenceOverrides" => {
                                "2022-11-30T16:45:00" => {
                                    "start" => "2022-12-01T16:45:00",
                                }
                            }
                        }
                    }}, "R1"]]);
    my $id = $res->[0][1]{created}{"1"}{id};

    xlog $self, "verify invitation sent from organizer to attendees";
    my $data = $self->{instance}->getnotify();
    my @imips = grep { $_->{METHOD} eq 'imip' } @$data;
    my $imip = $imips[0];
    $self->assert_not_null($imip);

    my $payload = decode_json($imip->{MESSAGE});
    my $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/set", $payload->{schedulingMechanism});
    $self->assert_str_equals("cassandane\@example.com", $payload->{sender});
    $self->assert_matches(qr/(bugs|rr)\@looneytunes.com/, $payload->{recipient});
    $self->assert_num_equals(1, $payload->{patch}{sequence});
    $self->assert($ical =~ "METHOD:REQUEST");
    $self->assert($ical =~ "SEQUENCE:1");
    $self->assert($ical =~ "PARTSTAT=NEEDS-ACTION");

    $imip = $imips[1];
    $self->assert_not_null($imip);

    $payload = decode_json($imip->{MESSAGE});
    $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/set", $payload->{schedulingMechanism});
    $self->assert_str_equals("cassandane\@example.com", $payload->{sender});
    $self->assert_matches(qr/(bugs|rr)\@looneytunes.com/, $payload->{recipient});
    $self->assert_num_equals(1, $payload->{patch}{sequence});
    $self->assert($ical =~ "METHOD:REQUEST");
    $self->assert($ical =~ "SEQUENCE:1");
    $self->assert($ical =~ "PARTSTAT=NEEDS-ACTION");

    xlog $self, "set attendee status";
    $res = $jmap->CallMethods([['CalendarEvent/participantReply', {
        eventId => $id,
        participantEmail => "bugs\@looneytunes.com",
        updates => {
            participationStatus => "accepted"
        }
    }, "R2"]]);
    $self->assert_str_equals("1.1", $res->[0][1]{scheduleStatus});

    xlog $self, "verify reply sent from attendee to organizer";
    $data = $self->{instance}->getnotify();
    @imips = grep { $_->{METHOD} eq 'imip' } @$data;
    $imip = $imips[0];
    $self->assert_not_null($imip);

    $payload = decode_json($imip->{MESSAGE});
    $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/participantReply",
                             $payload->{schedulingMechanism});
    $self->assert_str_equals("bugs\@looneytunes.com", $payload->{sender});
    $self->assert_str_equals("cassandane\@example.com", $payload->{recipient});
    $self->assert_num_equals(1, $payload->{jsevent}{sequence});
    $self->assert($ical =~ "METHOD:REPLY");
    $self->assert($ical =~ "SEQUENCE:1");
    $self->assert($ical =~ "PARTSTAT=ACCEPTED");

    xlog $self, "verify updated request sent from organizer to attendee";
    $imip = $imips[1];
    $self->assert_not_null($imip);

    $payload = decode_json($imip->{MESSAGE});
    $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/participantReply",
                             $payload->{schedulingMechanism});
    $self->assert_str_equals("cassandane\@example.com", $payload->{sender});
    $self->assert_str_equals("bugs\@looneytunes.com", $payload->{recipient});
    $self->assert_num_equals(1, $payload->{jsevent}{sequence});
    $self->assert($ical =~ "METHOD:REQUEST");
    $self->assert($ical =~ "SEQUENCE:1");
    $self->assert($ical =~ "PARTSTAT=ACCEPTED");

    my ($maj, $min) = Cassandane::Instance->get_version();
    if ($maj > 3 || ($maj == 3 && $min >= 9)) {
        xlog $self, "actually update attendee status on the event";
        $res = $jmap->CallMethods([['CalendarEvent/set', {
            update => {
                $id => { "participants/att1/participationStatus" => "accepted" }
            }
        }, "R1"]]);

        xlog $self, "set attendee status again";
        $res = $jmap->CallMethods([['CalendarEvent/participantReply', {
            eventId => $id,
            participantEmail => "bugs\@looneytunes.com",
            updates => {
                participationStatus => "accepted"
            }
        }, "R2"]]);
        $self->assert_str_equals("2.0", $res->[0][1]{scheduleStatus});

        xlog $self, "verify that NO iMIP messages are sent to organizer/attendee";
        $data = $self->{instance}->getnotify();
        @imips = grep { $_->{METHOD} eq 'imip' } @$data;
        $self->assert_null($imips);
    }

    xlog $self, "set attendee status on override";
    $res = $jmap->CallMethods([['CalendarEvent/participantReply', {
        eventId => encode_eventid(substr($id, 2), "20221130T164500"),
        participantEmail => "rr\@looneytunes.com",
        updates => {
            participationStatus => "declined"
        }
    }, "R2"]]);
    $self->assert_str_equals("1.1", $res->[0][1]{scheduleStatus});

    xlog $self, "verify reply sent from attendee to organizer";
    $data = $self->{instance}->getnotify();
    @imips = grep { $_->{METHOD} eq 'imip' } @$data;
    $imip = $imips[0];
    $self->assert_not_null($imip);

    $payload = decode_json($imip->{MESSAGE});
    $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/participantReply",
                             $payload->{schedulingMechanism});
    $self->assert_str_equals("rr\@looneytunes.com", $payload->{sender});
    $self->assert_str_equals("cassandane\@example.com", $payload->{recipient});
    $self->assert_num_equals(2, $payload->{jsevent}{sequence});
    $self->assert($ical =~ "METHOD:REPLY");
    $self->assert($ical =~ "SEQUENCE:2");
    $self->assert($ical =~ "PARTSTAT=DECLINED");

    xlog $self, "verify updated request sent from organizer to attendee";
    $imip = $imips[1];
    $self->assert_not_null($imip);

    $payload = decode_json($imip->{MESSAGE});
    $ical = $payload->{ical};

    $self->assert_str_equals("CalendarEvent/participantReply",
                             $payload->{schedulingMechanism});
    $self->assert_str_equals("cassandane\@example.com", $payload->{sender});
    $self->assert_str_equals("rr\@looneytunes.com", $payload->{recipient});
    $self->assert_num_equals(2, $payload->{jsevent}{sequence});
    $self->assert($ical =~ "METHOD:REQUEST");
    $self->assert($ical =~ "SEQUENCE:2");
    $self->assert($ical =~ "PARTSTAT=DECLINED");

    if ($maj > 3 || ($maj == 3 && $min >= 9)) {
        xlog $self, "actually update attendee status on the event";
        my $res = $jmap->CallMethods([['CalendarEvent/set', {
            update => {
                $id => { "participants/att2/participationStatus" => "declined" }
            }
        }, "R1"]]);

        xlog $self, "set attendee status again";
        $res = $jmap->CallMethods([['CalendarEvent/participantReply', {
            eventId => encode_eventid(substr($id, 2), "20221130T164500"),
            participantEmail => "rr\@looneytunes.com",
            updates => {
                participationStatus => "declined"
            }
        }, "R2"]]);
        $self->assert_str_equals("2.0", $res->[0][1]{scheduleStatus});

        xlog $self, "verify that NO iMIP messages are sent to organizer/attendee";
        $data = $self->{instance}->getnotify();
        @imips = grep { $_->{METHOD} eq 'imip' } @$data;
        $self->assert_null($imips);
    }
}
