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

import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.SnoozeCriterion;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.server.UiServiceTestCase;

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

import java.util.ArrayList;
import java.util.List;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationListenerServiceTest extends UiServiceTestCase {

    private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};

    @Test
    public void testGetActiveNotifications_notNull() throws Exception {
        TestListenerService service = new TestListenerService();
        INotificationManager noMan = service.getNoMan();
        when(noMan.getActiveNotificationsFromListener(any(), any(), anyInt())).thenReturn(null);

        assertNotNull(service.getActiveNotifications());
        assertNotNull(service.getActiveNotifications(NotificationListenerService.TRIM_FULL));
        assertNotNull(service.getActiveNotifications(new String[0]));
        assertNotNull(service.getActiveNotifications(
                new String[0], NotificationListenerService.TRIM_LIGHT));
    }

    @Test
    public void testRanking() {
        TestListenerService service = new TestListenerService();
        service.applyUpdateLocked(generateUpdate());
        for (int i = 0; i < mKeys.length; i++) {
            String key = mKeys[i];
            Ranking ranking = new Ranking();
            service.getCurrentRanking().getRanking(key, ranking);
            assertEquals(getVisibilityOverride(i), ranking.getVisibilityOverride());
            assertEquals(getOverrideGroupKey(key), ranking.getOverrideGroupKey());
            assertEquals(!isIntercepted(i), ranking.matchesInterruptionFilter());
            assertEquals(getSuppressedVisualEffects(i), ranking.getSuppressedVisualEffects());
            assertEquals(getImportance(i), ranking.getImportance());
            assertEquals(getExplanation(key), ranking.getImportanceExplanation());
            assertEquals(getChannel(key, i), ranking.getChannel());
            assertEquals(getPeople(key, i), ranking.getAdditionalPeople());
            assertEquals(getSnoozeCriteria(key, i), ranking.getSnoozeCriteria());
            assertEquals(getShowBadge(i), ranking.canShowBadge());
            assertEquals(getUserSentiment(i), ranking.getUserSentiment());
            assertEquals(getHidden(i), ranking.isSuspended());
            assertEquals(lastAudiblyAlerted(i), ranking.getLastAudiblyAlertedMillis());
            assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
            assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
            assertEquals(canBubble(i), ranking.canBubble());
        }
    }

    private NotificationRankingUpdate generateUpdate() {
        List<String> interceptedKeys = new ArrayList<>();
        Bundle visibilityOverrides = new Bundle();
        Bundle overrideGroupKeys = new Bundle();
        Bundle suppressedVisualEffects = new Bundle();
        Bundle explanation = new Bundle();
        Bundle channels = new Bundle();
        Bundle overridePeople = new Bundle();
        Bundle snoozeCriteria = new Bundle();
        Bundle showBadge = new Bundle();
        int[] importance = new int[mKeys.length];
        Bundle userSentiment = new Bundle();
        Bundle mHidden = new Bundle();
        Bundle smartActions = new Bundle();
        Bundle smartReplies = new Bundle();
        Bundle lastAudiblyAlerted = new Bundle();
        Bundle noisy = new Bundle();
        boolean[] canBubble = new boolean[mKeys.length];

        for (int i = 0; i < mKeys.length; i++) {
            String key = mKeys[i];
            visibilityOverrides.putInt(key, getVisibilityOverride(i));
            overrideGroupKeys.putString(key, getOverrideGroupKey(key));
            if (isIntercepted(i)) {
                interceptedKeys.add(key);
            }
            suppressedVisualEffects.putInt(key, getSuppressedVisualEffects(i));
            importance[i] = getImportance(i);
            explanation.putString(key, getExplanation(key));
            channels.putParcelable(key, getChannel(key, i));
            overridePeople.putStringArrayList(key, getPeople(key, i));
            snoozeCriteria.putParcelableArrayList(key, getSnoozeCriteria(key, i));
            showBadge.putBoolean(key, getShowBadge(i));
            userSentiment.putInt(key, getUserSentiment(i));
            mHidden.putBoolean(key, getHidden(i));
            smartActions.putParcelableArrayList(key, getSmartActions(key, i));
            smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
            lastAudiblyAlerted.putLong(key, lastAudiblyAlerted(i));
            noisy.putBoolean(key, getNoisy(i));
            canBubble[i] = canBubble(i);
        }
        NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
                interceptedKeys.toArray(new String[0]), visibilityOverrides,
                suppressedVisualEffects, importance, explanation, overrideGroupKeys,
                channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
                smartActions, smartReplies, lastAudiblyAlerted, noisy, canBubble);
        return update;
    }

    private int getVisibilityOverride(int index) {
        return index * 9;
    }

    private String getOverrideGroupKey(String key) {
        return key + key;
    }

    private boolean isIntercepted(int index) {
        return index % 2 == 0;
    }

    private int getSuppressedVisualEffects(int index) {
        return index * 2;
    }

    private int getImportance(int index) {
        return index;
    }

    private String getExplanation(String key) {
        return key + "explain";
    }

    private NotificationChannel getChannel(String key, int index) {
        return new NotificationChannel(key, key, getImportance(index));
    }

    private boolean getShowBadge(int index) {
        return index % 3 == 0;
    }

    private int getUserSentiment(int index) {
        switch(index % 3) {
            case 0:
                return USER_SENTIMENT_NEGATIVE;
            case 1:
                return USER_SENTIMENT_NEUTRAL;
            case 2:
                return USER_SENTIMENT_POSITIVE;
        }
        return USER_SENTIMENT_NEUTRAL;
    }

    private boolean getHidden(int index) {
        return index % 2 == 0;
    }

    private long lastAudiblyAlerted(int index) {
        return index * 2000;
    }

    private boolean getNoisy(int index) {
        return index < 1;
    }

    private ArrayList<String> getPeople(String key, int index) {
        ArrayList<String> people = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            people.add(i + key);
        }
        return people;
    }

    private ArrayList<SnoozeCriterion> getSnoozeCriteria(String key, int index) {
        ArrayList<SnoozeCriterion> snooze = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            snooze.add(new SnoozeCriterion(key + i, getExplanation(key), key));
        }
        return snooze;
    }

    private ArrayList<Notification.Action> getSmartActions(String key, int index) {
        ArrayList<Notification.Action> actions = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            PendingIntent intent = PendingIntent.getBroadcast(
                    getContext(),
                    index /*requestCode*/,
                    new Intent("ACTION_" + key),
                    0 /*flags*/);
            actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build());
        }
        return actions;
    }

    private ArrayList<CharSequence> getSmartReplies(String key, int index) {
        ArrayList<CharSequence> choices = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            choices.add("choice_" + key + "_" + i);
        }
        return choices;
    }

    private boolean canBubble(int index) {
        return index % 4 == 0;
    }

    private void assertActionsEqual(
            List<Notification.Action> expecteds, List<Notification.Action> actuals) {
        assertEquals(expecteds.size(), actuals.size());
        for (int i = 0; i < expecteds.size(); i++) {
            Notification.Action expected = expecteds.get(i);
            Notification.Action actual = actuals.get(i);
            assertEquals(expected.title, actual.title);
        }
    }

    public static class TestListenerService extends NotificationListenerService {
        private final IBinder binder = new LocalBinder();

        public TestListenerService() {
            mWrapper = mock(NotificationListenerWrapper.class);
            mNoMan = mock(INotificationManager.class);
        }

        INotificationManager getNoMan() {
            return mNoMan;
        }

        @Override
        public IBinder onBind(Intent intent) {
            super.onBind(intent);
            return binder;
        }

        public class LocalBinder extends Binder {
            TestListenerService getService() {
                return TestListenerService.this;
            }
        }
    }
}
