#!perl
use Cassandane::Tiny;

sub test_dblookup_uid2groups
    :NoAltNameSpace
    ($self)
{
    my $jmap = $self->{jmap};
    my $imap = $self->{store}->get_client();
    my $admin = $self->{adminstore}->get_client();
    my $http = $self->{instance}->get_service("http");

    xlog "Create shared addressbooks";
    $admin->create("user.other");
    $admin->create("user.other2");

    my $admin_user = $self->{instance}->create_user_without_setup('admin');
    my $other_user = $self->{instance}->create_user_without_setup('other');
    my $other2_user = $self->{instance}->create_user_without_setup('other2');

    my $adminJmap = $admin_user->jmap;
    my $otherJmap = $other_user->jmap;
    my $other2Jmap = $other2_user->jmap;

    xlog $self, "Enable compactids";
    $self->{instance}->run_command({ cyrus => 1 },
                                   'ctl_conversationsdb', '-I', 'on', 'other');
    $self->{instance}->run_command({ cyrus => 1 },
                                   'ctl_conversationsdb', '-I', 'on', 'other2');

    xlog $self, "Create and share addressbooks";
    $admin->create("user.other.#addressbooks.Shared", ['TYPE', 'ADDRESSBOOK']);
    $admin->setacl("user.other.#addressbooks.Shared", "cassandane", "lr") or die;
    $admin->create("user.other2.#addressbooks.Shared", ['TYPE', 'ADDRESSBOOK']);
    $admin->setacl("user.other2.#addressbooks.Shared", "other", "lr") or die;

    my $using = [
        'urn:ietf:params:jmap:core',
        'urn:ietf:params:jmap:contacts',
        'https://cyrusimap.org/ns/jmap/contacts'
    ];

    xlog "Get addressbook Ids";
    my $res = $otherJmap->CallMethods([
        ['AddressBook/get', {
            properties => [ 'name' ]
        }, 'R1'],
    ], $using);
    my %m = map { $_->{name} => $_ } @{$res->[0][1]{list}};
    my $otherSharedAbookId = $m{"Shared"}{id};

    $res = $other2Jmap->CallMethods([
        ['AddressBook/get', {
            properties => [ 'name' ]
        }, 'R1'],
    ], $using);
    %m = map { $_->{name} => $_ } @{$res->[0][1]{list}};
    my $other2SharedAbookId = $m{"Shared"}{id};

    xlog "Create contact in own addressbook";
    $res = $jmap->CallMethods([
        ['Contact/set', {
            create => {
                ownContact => {
                    firstName => 'Own',
                    lastName => 'Contact',
                }
            }
        }, 'R1'],
    ], $using);
    my $ownContactId = $res->[0][1]{created}{ownContact}{id};
    $self->assert_not_null($ownContactId);
    my $ownContactUid = $res->[0][1]{created}{ownContact}{uid};
    $self->assert_not_null($ownContactUid);

    xlog "Create contacts in shared addressbooks";
    $res = $otherJmap->CallMethods([
        ['Contact/set', {
            create => {
                sharedContact => {
                    firstName => 'Other',
                    lastName => 'Contact',
                    addressbookId => 'Shared'
                }
            }
        }, 'R1'],
    ], $using);
    my $otherSharedContactId = $res->[0][1]{created}{sharedContact}{id};
    $self->assert_not_null($otherSharedContactId);
    my $otherSharedContactUid = $res->[0][1]{created}{sharedContact}{uid};
    $self->assert_not_null($otherSharedContactUid);

    $res = $other2Jmap->CallMethods([
        ['Contact/set', {
            create => {
                sharedContact => {
                    firstName => 'Other2',
                    lastName => 'Contact',
                    addressbookId => 'Shared'
                }
            }
        }, 'R1'],
    ], $using);
    my $other2SharedContactId = $res->[0][1]{created}{sharedContact}{id};
    $self->assert_not_null($other2SharedContactId);
    my $other2SharedContactUid = $res->[0][1]{created}{sharedContact}{uid};
    $self->assert_not_null($other2SharedContactUid);

    xlog "Create group in own addressbook";
    $res = $jmap->CallMethods([
        ['ContactGroup/set', {
            create => {
                ownGroup => {
                    name => 'owngroup',
                    contactIds => [ $ownContactId ],
                    otherAccountContactIds => {
                        other => [ $otherSharedContactId ]
                    }
                }
            }
        }, 'R1'],
    ], $using);
    my $ownGroupUid = $res->[0][1]{created}{ownGroup}{uid};
    $self->assert_not_null($ownGroupUid);

    xlog "Create group in shared addressbook";
    $res = $otherJmap->CallMethods([
        ['ContactGroup/set', {
            create => {
                otherGroup => {
                    name => 'othergroup',
                    contactIds => [ $otherSharedContactId ],
                    otherAccountContactIds => {
                        other2 => [ $other2SharedContactId ]
                    },
                    addressbookId => 'Shared'
                }
            }
        }, 'R1'],
    ], $using);
    my $otherGroupUid = $res->[0][1]{created}{otherGroup}{uid};
    $self->assert_not_null($otherGroupUid);

    xlog "Lookup own groups containing ownContactUid";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $ownContactUid
    });
    $self->assert_cmp_deeply(
        superhashof({
            $ownGroupUid => 'owngroup'
        }),
        $res->{payload},
    );

    xlog "Lookup own groups containing ownContactUid in other user";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $ownContactUid,
        OtherUser => 'other'
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup own groups containing otherSharedContactUid";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $otherSharedContactUid,
        OtherUser => 'other'
    });
    $self->assert_cmp_deeply(
        superhashof({
            $ownGroupUid => 'owngroup'
        }),
        $res->{payload},
    );

    xlog "Lookup own groups containing otherSharedContactUid in own user";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $otherSharedContactUid
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup other groups containing otherSharedContactUid in Default abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $otherSharedContactUid,
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup other groups containing otherSharedContactUid in Shared abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $otherSharedContactUid,
        Mailbox => 'Shared'
    });
    $self->assert_cmp_deeply(
        superhashof({
            $otherGroupUid => 'othergroup'
        }),
        $res->{payload},
    );

    xlog "Lookup other groups containing other2SharedContactUid in Shared abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $other2SharedContactUid,
        OtherUser => 'other2',
        Mailbox => 'Shared'
    });
    $self->assert_cmp_deeply(
        superhashof({
            $otherGroupUid => 'othergroup'
        }),
        $res->{payload},
    );

    xlog "Create group in own addressbook";
    $res = $jmap->CallMethods([
        ['ContactCard/set', {
            create => {
                ownGroup => {
                    '@type' => 'Card',
                    version => '1.0',
                    kind => 'group',
                    name => { full => 'owngroup2' },
                    members => {
                        $ownContactUid => JSON::true,
                        $otherSharedContactUid => JSON::true,
                    }
                }
            }
        }, 'R1'],
    ], $using);
    my $ownGroupUid2 = $res->[0][1]{created}{ownGroup}{uid};
    $self->assert_not_null($ownGroupUid2);

    xlog "Create group in shared addressbook";
    $res = $otherJmap->CallMethods([
        ['ContactCard/set', {
            create => {
                otherGroup => {
                    '@type' => 'Card',
                    version => '1.0',
                    kind => 'group',
                    name => { full => 'othergroup2' },
                    members => {
                        $otherSharedContactId => JSON::true,
                        $other2SharedContactId => JSON::true
                    },
                    addressBookIds => { $otherSharedAbookId => JSON::true }
                }
            }
        }, 'R1'],
    ], $using);
    my $otherGroupUid2 = $res->[0][1]{created}{otherGroup}{uid};
    $self->assert_not_null($otherGroupUid2);

    xlog "Lookup own groups containing ownContactUid";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $ownContactUid
    });
    $self->assert_cmp_deeply(
        superhashof({
            $ownGroupUid => 'owngroup',
            $ownGroupUid2 => 'owngroup2'
        }),
        $res->{payload},
    );

    xlog "Lookup own groups containing ownContactUid in other user";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $ownContactUid,
        OtherUser => 'other'
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup own groups containing otherSharedContactUid";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $otherSharedContactUid,
        OtherUser => 'other'
    });

    $self->assert_cmp_deeply(
        superhashof({
            $ownGroupUid => 'owngroup',
            $ownGroupUid2 => 'owngroup2'
        }),
        $res->{payload},
    );

    xlog "Lookup own groups containing otherSharedContactUid in own user";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'cassandane',
        Key => $otherSharedContactUid
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup other groups containing otherSharedContactUid in Default abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $otherSharedContactUid,
    });
    $self->assert_deep_equals({}, $res->{payload});

    xlog "Lookup other groups containing otherSharedContactUid in Shared abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $otherSharedContactUid,
        Mailbox => 'Shared'
    });
    $self->assert_cmp_deeply(
        superhashof({
            $otherGroupUid => 'othergroup',
            $otherGroupUid2 => 'othergroup2'
        }),
        $res->{payload},
    );

    xlog "Lookup other groups containing other2SharedContactUid in Shared abook";
    $res = $self->dblookup('/dblookup/uid2groups' => {
        User => 'other',
        Key => $other2SharedContactUid,
        OtherUser => 'other2',
        Mailbox => 'Shared'
    });
    $self->assert_cmp_deeply(
        superhashof({
            $otherGroupUid => 'othergroup',
            $otherGroupUid2 => 'othergroup2'
        }),
        $res->{payload},
    );
}

