/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.people.data;

import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
import static android.app.people.ConversationStatus.ACTIVITY_GAME;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import android.app.people.ConversationStatus;
import android.content.LocusId;
import android.content.pm.ShortcutInfo;
import android.net.Uri;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class ConversationInfoTest {

    private static final String SHORTCUT_ID = "abc";
    private static final LocusId LOCUS_ID = new LocusId("def");
    private static final Uri CONTACT_URI = Uri.parse("tel:+1234567890");
    private static final String PHONE_NUMBER = "+1234567890";
    private static final String NOTIFICATION_CHANNEL_ID = "test : abc";
    private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";

    @Test
    public void testBuild() {
        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();

        ConversationInfo conversationInfo = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .setLocusId(LOCUS_ID)
                .setContactUri(CONTACT_URI)
                .setContactPhoneNumber(PHONE_NUMBER)
                .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
                .setLastEventTimestamp(100L)
                .setCreationTimestamp(200L)
                .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
                        | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
                .setImportant(true)
                .setNotificationSilenced(true)
                .setBubbled(true)
                .setDemoted(true)
                .setPersonImportant(true)
                .setPersonBot(true)
                .setContactStarred(true)
                .addOrUpdateStatus(cs)
                .addOrUpdateStatus(cs2)
                .build();

        assertEquals(SHORTCUT_ID, conversationInfo.getShortcutId());
        assertEquals(LOCUS_ID, conversationInfo.getLocusId());
        assertEquals(CONTACT_URI, conversationInfo.getContactUri());
        assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber());
        assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
                conversationInfo.getParentNotificationChannelId());
        assertEquals(100L, conversationInfo.getLastEventTimestamp());
        assertEquals(200L, conversationInfo.getCreationTimestamp());
        assertTrue(conversationInfo.isShortcutLongLived());
        assertTrue(conversationInfo.isShortcutCachedForNotification());
        assertTrue(conversationInfo.isImportant());
        assertTrue(conversationInfo.isNotificationSilenced());
        assertTrue(conversationInfo.isBubbled());
        assertTrue(conversationInfo.isDemoted());
        assertTrue(conversationInfo.isPersonImportant());
        assertTrue(conversationInfo.isPersonBot());
        assertTrue(conversationInfo.isContactStarred());
        assertThat(conversationInfo.getStatuses()).contains(cs);
        assertThat(conversationInfo.getStatuses()).contains(cs2);
    }

    @Test
    public void testBuildEmpty() {
        ConversationInfo conversationInfo = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .build();

        assertEquals(SHORTCUT_ID, conversationInfo.getShortcutId());
        assertNull(conversationInfo.getLocusId());
        assertNull(conversationInfo.getContactUri());
        assertNull(conversationInfo.getContactPhoneNumber());
        assertNull(conversationInfo.getNotificationChannelId());
        assertNull(conversationInfo.getParentNotificationChannelId());
        assertEquals(0L, conversationInfo.getLastEventTimestamp());
        assertEquals(0L, conversationInfo.getCreationTimestamp());
        assertFalse(conversationInfo.isShortcutLongLived());
        assertFalse(conversationInfo.isShortcutCachedForNotification());
        assertFalse(conversationInfo.isImportant());
        assertFalse(conversationInfo.isNotificationSilenced());
        assertFalse(conversationInfo.isBubbled());
        assertFalse(conversationInfo.isDemoted());
        assertFalse(conversationInfo.isPersonImportant());
        assertFalse(conversationInfo.isPersonBot());
        assertFalse(conversationInfo.isContactStarred());
        assertThat(conversationInfo.getStatuses()).isNotNull();
        assertThat(conversationInfo.getStatuses()).isEmpty();
    }

    @Test
    public void testBuildFromAnotherConversationInfo() {
        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();

        ConversationInfo source = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .setLocusId(LOCUS_ID)
                .setContactUri(CONTACT_URI)
                .setContactPhoneNumber(PHONE_NUMBER)
                .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
                .setLastEventTimestamp(100L)
                .setCreationTimestamp(200L)
                .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
                .setImportant(true)
                .setNotificationSilenced(true)
                .setBubbled(true)
                .setPersonImportant(true)
                .setPersonBot(true)
                .setContactStarred(true)
                .addOrUpdateStatus(cs)
                .addOrUpdateStatus(cs2)
                .build();

        ConversationInfo destination = new ConversationInfo.Builder(source)
                .setImportant(false)
                .setContactStarred(false)
                .build();

        assertEquals(SHORTCUT_ID, destination.getShortcutId());
        assertEquals(LOCUS_ID, destination.getLocusId());
        assertEquals(CONTACT_URI, destination.getContactUri());
        assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
        assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
        assertEquals(100L, destination.getLastEventTimestamp());
        assertEquals(200L, destination.getCreationTimestamp());
        assertTrue(destination.isShortcutLongLived());
        assertFalse(destination.isImportant());
        assertTrue(destination.isNotificationSilenced());
        assertTrue(destination.isBubbled());
        assertTrue(destination.isPersonImportant());
        assertTrue(destination.isPersonBot());
        assertFalse(destination.isContactStarred());
        assertThat(destination.getStatuses()).contains(cs);
        assertThat(destination.getStatuses()).contains(cs2);
    }

    @Test
    public void testBuildFromAnotherConversation_identicalConversation() {
        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();

        ConversationInfo source = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .setLocusId(LOCUS_ID)
                .setContactUri(CONTACT_URI)
                .setContactPhoneNumber(PHONE_NUMBER)
                .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
                .setLastEventTimestamp(100L)
                .setCreationTimestamp(200L)
                .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
                .setImportant(true)
                .setNotificationSilenced(true)
                .setBubbled(true)
                .setPersonImportant(true)
                .setPersonBot(true)
                .setContactStarred(true)
                .addOrUpdateStatus(cs)
                .addOrUpdateStatus(cs2)
                .build();

        ConversationInfo destination = new ConversationInfo.Builder(source).build();

        assertEquals(SHORTCUT_ID, destination.getShortcutId());
        assertEquals(LOCUS_ID, destination.getLocusId());
        assertEquals(CONTACT_URI, destination.getContactUri());
        assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
        assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
        assertEquals(100L, destination.getLastEventTimestamp());
        assertEquals(200L, destination.getCreationTimestamp());
        assertTrue(destination.isShortcutLongLived());
        assertTrue(destination.isImportant());
        assertTrue(destination.isNotificationSilenced());
        assertTrue(destination.isBubbled());
        assertTrue(destination.isPersonImportant());
        assertTrue(destination.isPersonBot());
        assertTrue(destination.isContactStarred());
        assertThat(destination.getStatuses()).contains(cs);
        assertThat(destination.getStatuses()).contains(cs2);
        // Also check equals() implementation
        assertTrue(source.equals(destination));
        assertTrue(destination.equals(source));
    }

    @Test
    public void testBuildFromBackupPayload() {
        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();

        ConversationInfo conversationInfo = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .setLocusId(LOCUS_ID)
                .setContactUri(CONTACT_URI)
                .setContactPhoneNumber(PHONE_NUMBER)
                .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
                .setLastEventTimestamp(100L)
                .setCreationTimestamp(200L)
                .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
                        | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
                .setImportant(true)
                .setNotificationSilenced(true)
                .setBubbled(true)
                .setDemoted(true)
                .setPersonImportant(true)
                .setPersonBot(true)
                .setContactStarred(true)
                .addOrUpdateStatus(cs)
                .addOrUpdateStatus(cs2)
                .build();

        ConversationInfo conversationInfoFromBackup =
                ConversationInfo.readFromBackupPayload(conversationInfo.getBackupPayload());

        assertEquals(SHORTCUT_ID, conversationInfoFromBackup.getShortcutId());
        assertEquals(LOCUS_ID, conversationInfoFromBackup.getLocusId());
        assertEquals(CONTACT_URI, conversationInfoFromBackup.getContactUri());
        assertEquals(PHONE_NUMBER, conversationInfoFromBackup.getContactPhoneNumber());
        assertEquals(
                NOTIFICATION_CHANNEL_ID, conversationInfoFromBackup.getNotificationChannelId());
        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
                conversationInfoFromBackup.getParentNotificationChannelId());
        assertEquals(100L, conversationInfoFromBackup.getLastEventTimestamp());
        assertEquals(200L, conversationInfoFromBackup.getCreationTimestamp());
        assertTrue(conversationInfoFromBackup.isShortcutLongLived());
        assertTrue(conversationInfoFromBackup.isShortcutCachedForNotification());
        assertTrue(conversationInfoFromBackup.isImportant());
        assertTrue(conversationInfoFromBackup.isNotificationSilenced());
        assertTrue(conversationInfoFromBackup.isBubbled());
        assertTrue(conversationInfoFromBackup.isDemoted());
        assertTrue(conversationInfoFromBackup.isPersonImportant());
        assertTrue(conversationInfoFromBackup.isPersonBot());
        assertTrue(conversationInfoFromBackup.isContactStarred());
        // ConversationStatus is a transient object and not persisted
    }

    @Test
    public void testBuildFromProtoPayload() throws Exception {
        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();

        ConversationInfo conversationInfo = new ConversationInfo.Builder()
                .setShortcutId(SHORTCUT_ID)
                .setLocusId(LOCUS_ID)
                .setContactUri(CONTACT_URI)
                .setContactPhoneNumber(PHONE_NUMBER)
                .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
                .setLastEventTimestamp(100L)
                .setCreationTimestamp(200L)
                .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
                        | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
                .setImportant(true)
                .setNotificationSilenced(true)
                .setBubbled(true)
                .setDemoted(true)
                .setPersonImportant(true)
                .setPersonBot(true)
                .setContactStarred(true)
                .addOrUpdateStatus(cs)
                .addOrUpdateStatus(cs2)
                .build();

        final ProtoOutputStream protoOutputStream = new ProtoOutputStream();
        conversationInfo.writeToProto(protoOutputStream);
        ConversationInfo conversationInfoFromBackup =
                ConversationInfo.readFromProto(new ProtoInputStream(protoOutputStream.getBytes()));

        assertEquals(SHORTCUT_ID, conversationInfoFromBackup.getShortcutId());
        assertEquals(LOCUS_ID, conversationInfoFromBackup.getLocusId());
        assertEquals(CONTACT_URI, conversationInfoFromBackup.getContactUri());
        assertEquals(PHONE_NUMBER, conversationInfoFromBackup.getContactPhoneNumber());
        assertEquals(
                NOTIFICATION_CHANNEL_ID, conversationInfoFromBackup.getNotificationChannelId());
        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
                conversationInfoFromBackup.getParentNotificationChannelId());
        assertEquals(100L, conversationInfoFromBackup.getLastEventTimestamp());
        assertEquals(200L, conversationInfoFromBackup.getCreationTimestamp());
        assertTrue(conversationInfoFromBackup.isShortcutLongLived());
        assertTrue(conversationInfoFromBackup.isShortcutCachedForNotification());
        assertTrue(conversationInfoFromBackup.isImportant());
        assertTrue(conversationInfoFromBackup.isNotificationSilenced());
        assertTrue(conversationInfoFromBackup.isBubbled());
        assertTrue(conversationInfoFromBackup.isDemoted());
        assertTrue(conversationInfoFromBackup.isPersonImportant());
        assertTrue(conversationInfoFromBackup.isPersonBot());
        assertTrue(conversationInfoFromBackup.isContactStarred());
        // ConversationStatus is a transient object and not persisted
    }
}
