/*
 * 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.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;
    }
}
