/*
 * Copyright (C) 2016 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.contacts;

import android.annotation.TargetApi;
import android.app.job.JobScheduler;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.support.test.filters.SdkSuppress;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.contacts.common.test.mocks.MockContentProvider;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.mockito.ArgumentCaptor;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@TargetApi(Build.VERSION_CODES.N_MR1)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N_MR1)
@SmallTest
public class DynamicShortcutsTests extends AndroidTestCase {


    @Override
    protected void tearDown() throws Exception {
        super.tearDown();

        // Clean up the job if it was scheduled by these tests.
        final JobScheduler scheduler = (JobScheduler) getContext()
                .getSystemService(Context.JOB_SCHEDULER_SERVICE);
        scheduler.cancel(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID);
    }

    // Basic smoke test to make sure the queries executed by DynamicShortcuts are valid as well
    // as the integration with ShortcutManager. Note that this may change the state of the shortcuts
    // on the device it is executed on.
    public void test_refresh_doesntCrash() {
        final DynamicShortcuts sut = new DynamicShortcuts(getContext());
        sut.refresh();
        // Pass because it didn't throw an exception.
    }

    public void test_createShortcutFromRow_hasCorrectResult() {
        final DynamicShortcuts sut = createDynamicShortcuts();

        final Cursor row = queryResult(
                // ID, LOOKUP_KEY, DISPLAY_NAME_PRIMARY
                1l, "lookup_key", "John Smith"
        );

        row.moveToFirst();
        final ShortcutInfo shortcut = sut.builderForContactShortcut(row).build();

        assertEquals("lookup_key", shortcut.getId());
        assertEquals(Contacts.getLookupUri(1, "lookup_key"), shortcut.getIntent().getData());
        assertEquals(ContactsContract.QuickContact.ACTION_QUICK_CONTACT,
                shortcut.getIntent().getAction());
        assertEquals("John Smith", shortcut.getShortLabel());
        assertEquals("John Smith", shortcut.getLongLabel());
        assertEquals(1l, shortcut.getExtras().getLong(Contacts._ID));
    }

    public void test_builderForContactShortcut_returnsNullWhenNameIsNull() {
        final DynamicShortcuts sut = createDynamicShortcuts();

        final ShortcutInfo.Builder shortcut = sut.builderForContactShortcut(1l, "lookup_key", null);

        assertNull(shortcut);
    }

    public void test_builderForContactShortcut_ellipsizesLongNamesForLabels() {
        final DynamicShortcuts sut = createDynamicShortcuts();
        sut.setShortLabelMaxLength(5);
        sut.setLongLabelMaxLength(10);

        final ShortcutInfo shortcut = sut.builderForContactShortcut(1l, "lookup_key",
                "123456789 1011").build();

        assertEquals("1234…", shortcut.getShortLabel());
        assertEquals("123456789…", shortcut.getLongLabel());
    }

    public void test_updatePinned_disablesShortcutsForRemovedContacts() throws Exception {
        final ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
        when(mockShortcutManager.getPinnedShortcuts()).thenReturn(
                Collections.singletonList(makeDynamic(shortcutFor(1l, "key1", "name1"))));

        final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager);

        sut.updatePinned();

        verify(mockShortcutManager).disableShortcuts(
                eq(Collections.singletonList("key1")), anyString());
    }

    public void test_updatePinned_updatesExistingShortcutsWithMatchingKeys() throws Exception {
        final ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
        when(mockShortcutManager.getPinnedShortcuts()).thenReturn(
                Arrays.asList(
                        makeDynamic(shortcutFor(1l, "key1", "name1")),
                        makeDynamic(shortcutFor(2l, "key2", "name2")),
                        makeDynamic(shortcutFor(3l, "key3", "name3"))
                ));

        final DynamicShortcuts sut = createDynamicShortcuts(resolverWithExpectedQueries(
                queryForSingleRow(Contacts.getLookupUri(1l, "key1"), 11l, "key1", "New Name1"),
                queryForSingleRow(Contacts.getLookupUri(2l, "key2"), 2l, "key2", "name2"),
                queryForSingleRow(Contacts.getLookupUri(3l, "key3"), 33l, "key3", "name3")
        ), mockShortcutManager);

        sut.updatePinned();

        final ArgumentCaptor<List<ShortcutInfo>> updateArgs =
                ArgumentCaptor.forClass((Class) List.class);

        verify(mockShortcutManager).disableShortcuts(
                eq(Collections.<String>emptyList()), anyString());
        verify(mockShortcutManager).updateShortcuts(updateArgs.capture());

        final List<ShortcutInfo> arg = updateArgs.getValue();
        assertThat(arg.size(), equalTo(3));
        assertThat(arg.get(0),
                isShortcutForContact(11l, "key1", "New Name1"));
        assertThat(arg.get(1),
                isShortcutForContact(2l, "key2", "name2"));
        assertThat(arg.get(2),
                isShortcutForContact(33l, "key3", "name3"));
    }

    public void test_refresh_setsDynamicShortcutsToStrequentContacts() {
        final ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
        when(mockShortcutManager.getPinnedShortcuts()).thenReturn(
                Collections.<ShortcutInfo>emptyList());
        final DynamicShortcuts sut = createDynamicShortcuts(resolverWithExpectedQueries(
                queryFor(Contacts.CONTENT_STREQUENT_URI,
                        1l, "starred_key", "starred name",
                        2l, "freq_key", "freq name",
                        3l, "starred_2", "Starred Two")), mockShortcutManager);

        sut.refresh();

        final ArgumentCaptor<List<ShortcutInfo>> updateArgs =
                ArgumentCaptor.forClass((Class) List.class);

        verify(mockShortcutManager).setDynamicShortcuts(updateArgs.capture());

        final List<ShortcutInfo> arg = updateArgs.getValue();
        assertThat(arg.size(), equalTo(3));
        assertThat(arg.get(0), isShortcutForContact(1l, "starred_key", "starred name"));
        assertThat(arg.get(1), isShortcutForContact(2l, "freq_key", "freq name"));
        assertThat(arg.get(2), isShortcutForContact(3l, "starred_2", "Starred Two"));
    }

    public void test_refresh_skipsContactsWithNullName() {
        final ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
        when(mockShortcutManager.getPinnedShortcuts()).thenReturn(
                Collections.<ShortcutInfo>emptyList());
        final DynamicShortcuts sut = createDynamicShortcuts(resolverWithExpectedQueries(
                queryFor(Contacts.CONTENT_STREQUENT_URI,
                        1l, "key1", "first",
                        2l, "key2", "second",
                        3l, "key3", null,
                        4l, null, null,
                        5l, "key5", "fifth",
                        6l, "key6", "sixth")), mockShortcutManager);

        sut.refresh();

        final ArgumentCaptor<List<ShortcutInfo>> updateArgs =
                ArgumentCaptor.forClass((Class) List.class);

        verify(mockShortcutManager).setDynamicShortcuts(updateArgs.capture());

        final List<ShortcutInfo> arg = updateArgs.getValue();
        assertThat(arg.size(), equalTo(3));
        assertThat(arg.get(0), isShortcutForContact(1l, "key1", "first"));
        assertThat(arg.get(1), isShortcutForContact(2l, "key2", "second"));
        assertThat(arg.get(2), isShortcutForContact(5l, "key5", "fifth"));


        // Also verify that it doesn't crash if there are fewer than 3 valid strequent contacts
        createDynamicShortcuts(resolverWithExpectedQueries(
                queryFor(Contacts.CONTENT_STREQUENT_URI,
                        1l, "key1", "first",
                        2l, "key2", "second",
                        3l, "key3", null,
                        4l, null, null)), mock(ShortcutManager.class)).refresh();
    }


    public void test_handleFlagDisabled_stopsJob() {
        final ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
        final JobScheduler mockJobScheduler = mock(JobScheduler.class);
        final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager,
                mockJobScheduler);

        sut.handleFlagDisabled();

        verify(mockJobScheduler).cancel(eq(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID));
    }


    public void test_scheduleUpdateJob_schedulesJob() {
        final DynamicShortcuts sut = new DynamicShortcuts(getContext());
        sut.scheduleUpdateJob();
        assertThat(DynamicShortcuts.isJobScheduled(getContext()), Matchers.is(true));
    }

    private Matcher<ShortcutInfo> isShortcutForContact(final long id,
            final String lookupKey, final String name) {
        return new BaseMatcher<ShortcutInfo>() {
            @Override
            public boolean matches(Object o) {
                if (!(o instanceof  ShortcutInfo)) return false;
                final ShortcutInfo other = (ShortcutInfo)o;
                return id == other.getExtras().getLong(Contacts._ID)
                        && lookupKey.equals(other.getId())
                        && name.equals(other.getLongLabel())
                        && name.equals(other.getShortLabel());
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("Should be a shortcut for contact with _ID=" + id +
                        " lookup=" + lookupKey + " and display_name=" + name);
            }
        };
    }

    private ShortcutInfo shortcutFor(long contactId, String lookupKey, String name) {
        return new DynamicShortcuts(getContext())
                .builderForContactShortcut(contactId, lookupKey, name).build();
    }

    private ContentResolver emptyResolver() {
        final MockContentProvider provider = new MockContentProvider();
        provider.expect(MockContentProvider.Query.forAnyUri())
                .withAnyProjection()
                .withAnySelection()
                .withAnySortOrder()
                .returnEmptyCursor();
        return resolverWithContactsProvider(provider);
    }

    private MockContentProvider.Query queryFor(Uri uri, Object... rows) {
        final MockContentProvider.Query query = MockContentProvider.Query
                .forUrisMatching(uri.getAuthority(), uri.getPath())
                .withProjection(DynamicShortcuts.PROJECTION)
                .withAnySelection()
                .withAnySortOrder();

        populateQueryRows(query, DynamicShortcuts.PROJECTION.length, rows);
        return query;
    }

    private MockContentProvider.Query queryForSingleRow(Uri uri, Object... row) {
        return new MockContentProvider.Query(uri)
                .withProjection(DynamicShortcuts.PROJECTION)
                .withAnySelection()
                .withAnySortOrder()
                .returnRow(row);
    }

    private ContentResolver resolverWithExpectedQueries(MockContentProvider.Query... queries) {
        final MockContentProvider provider = new MockContentProvider();
        for (MockContentProvider.Query query : queries) {
            provider.expect(query);
        }
        return resolverWithContactsProvider(provider);
    }

    private ContentResolver resolverWithContactsProvider(ContentProvider provider) {
        final MockContentResolver resolver = new MockContentResolver();
        resolver.addProvider(ContactsContract.AUTHORITY, provider);
        return resolver;
    }

    private DynamicShortcuts createDynamicShortcuts() {
        return createDynamicShortcuts(emptyResolver(), mock(ShortcutManager.class));
    }


    private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver,
            ShortcutManager shortcutManager) {
        return createDynamicShortcuts(resolver, shortcutManager, mock(JobScheduler.class));
    }

    private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver,
            ShortcutManager shortcutManager, JobScheduler jobScheduler) {
        final DynamicShortcuts result = new DynamicShortcuts(getContext(), resolver,
                shortcutManager, jobScheduler);
        // Use very long label limits to make checking shortcuts easier to understand
        result.setShortLabelMaxLength(100);
        result.setLongLabelMaxLength(100);
        return result;
    }

    private void populateQueryRows(MockContentProvider.Query query, int numColumns,
            Object... rows) {
        for (int i = 0; i < rows.length; i += numColumns) {
            Object[] row = new Object[numColumns];
            for (int j = 0; j < numColumns; j++) {
                row[j] = rows[i + j];
            }
            query.returnRow(row);
        }
    }

    private Cursor queryResult(Object... values) {
        return queryResult(DynamicShortcuts.PROJECTION, values);
    }

    // Ugly hack because the API is hidden. Alternative is to actually set the shortcut on the real
    // ShortcutManager but this seems simpler for now.
    private ShortcutInfo makeDynamic(ShortcutInfo shortcutInfo) throws Exception {
        final Method addFlagsMethod = ShortcutInfo.class.getMethod("addFlags", int.class);
        // 1 = FLAG_DYNAMIC
        addFlagsMethod.invoke(shortcutInfo, 1);
        return shortcutInfo;
    }

    private Cursor queryResult(String[] columns, Object... values) {
        MatrixCursor result = new MatrixCursor(new String[] {
                Contacts._ID, Contacts.LOOKUP_KEY,
                Contacts.DISPLAY_NAME_PRIMARY
        });
        for (int i = 0; i < values.length; i += columns.length) {
            MatrixCursor.RowBuilder builder = result.newRow();
            for (int j = 0; j < columns.length; j++) {
                builder.add(values[i + j]);
            }
        }
        return result;
    }
}
