/*
 * 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.systemui.statusbar.notification.row;

import static android.service.notification.NotificationAssistantService.FEEDBACK_RATING;

import static com.android.systemui.statusbar.notification.AssistantFeedbackController.STATUS_ALERTED;
import static com.android.systemui.statusbar.notification.AssistantFeedbackController.STATUS_DEMOTED;
import static com.android.systemui.statusbar.notification.AssistantFeedbackController.STATUS_PROMOTED;
import static com.android.systemui.statusbar.notification.AssistantFeedbackController.STATUS_SILENCED;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.Html;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsContent {

    private static final String TAG = "FeedbackInfo";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private NotificationGuts mGutsContainer;
    private NotificationListenerService.Ranking mRanking;
    private PackageManager mPm;
    private String mAppName;
    private String mPkg;
    private NotificationEntry mEntry;

    private NotificationEntryManager mNotificationEntryManager;
    private IStatusBarService mStatusBarService;
    private AssistantFeedbackController mFeedbackController;
    private NotificationGutsManager mNotificationGutsManager;
    private NotificationMenuRowPlugin mMenuRowPlugin;
    private ExpandableNotificationRow mExpandableNotificationRow;

    public FeedbackInfo(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void bindGuts(
            final PackageManager pm,
            final StatusBarNotification sbn,
            final NotificationEntry entry,
            final ExpandableNotificationRow row,
            final AssistantFeedbackController controller) {
        mPkg = sbn.getPackageName();
        mPm = pm;
        mEntry = entry;
        mExpandableNotificationRow = row;
        mRanking = entry.getRanking();
        mFeedbackController = controller;
        mAppName = mPkg;
        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
        mStatusBarService = Dependency.get(IStatusBarService.class);
        mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);

        bindHeader();
        bindPrompt();
    }

    private void bindHeader() {
        // Package name
        Drawable pkgicon = null;
        ApplicationInfo info;
        try {
            info = mPm.getApplicationInfo(mPkg,
                    PackageManager.MATCH_UNINSTALLED_PACKAGES
                            | PackageManager.MATCH_DISABLED_COMPONENTS
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (info != null) {
                mAppName = String.valueOf(mPm.getApplicationLabel(info));
                pkgicon = mPm.getApplicationIcon(info);
            }
        } catch (PackageManager.NameNotFoundException e) {
            // app is gone, just show package name and generic icon
            pkgicon = mPm.getDefaultActivityIcon();
        }
        ((ImageView) findViewById(R.id.pkg_icon)).setImageDrawable(pkgicon);
        ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        if (mGutsContainer != null
                && event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (mGutsContainer.isExposed()) {
                event.getText().add(mContext.getString(
                        R.string.notification_channel_controls_opened_accessibility, mAppName));
            } else {
                event.getText().add(mContext.getString(
                        R.string.notification_channel_controls_closed_accessibility, mAppName));
            }
        }
    }

    private void bindPrompt() {
        final TextView prompt = findViewById(R.id.prompt);
        final TextView yes = findViewById(R.id.yes);
        final TextView no = findViewById(R.id.no);
        yes.setVisibility(View.VISIBLE);
        no.setVisibility(View.VISIBLE);
        yes.setOnClickListener(this::positiveFeedback);
        no.setOnClickListener(this::negativeFeedback);
        prompt.setText(Html.fromHtml(getPrompt()));
    }

    @SuppressLint("DefaultLocale")
    private String getPrompt() {
        StringBuilder sb = new StringBuilder();
        int status = mFeedbackController.getFeedbackStatus(mEntry);
        if (DEBUG) {
            sb.append(String.format(
                    "[DEBUG]: oldImportance=%d, newImportance=%d, ranking=%f\n\n",
                    mRanking.getChannel().getImportance(), mRanking.getImportance(),
                    mRanking.getRankingScore()));
        }
        if (status == STATUS_ALERTED) {
            sb.append(mContext.getText(R.string.feedback_alerted));
        } else if (status == STATUS_SILENCED) {
            sb.append(mContext.getText(R.string.feedback_silenced));
        } else if (status == STATUS_PROMOTED) {
            sb.append(mContext.getText(R.string.feedback_promoted));
        } else if (status == STATUS_DEMOTED) {
            sb.append(mContext.getText(R.string.feedback_demoted));
        }
        sb.append(" ");
        sb.append(mContext.getText(R.string.feedback_prompt));

        return sb.toString();
    }

    private void positiveFeedback(View v) {
        mGutsContainer.closeControls(v, false);
        handleFeedback(true);
    }

    private void negativeFeedback(View v) {
        mMenuRowPlugin = mExpandableNotificationRow.getProvider();
        NotificationMenuRowPlugin.MenuItem menuItem = null;
        if (mMenuRowPlugin != null) {
            menuItem = mMenuRowPlugin.getLongpressMenuItem(mContext);
        }

        mGutsContainer.closeControls(v, false);
        mNotificationGutsManager.openGuts(mExpandableNotificationRow, 0, 0, menuItem);
        handleFeedback(false);
    }

    private void handleFeedback(boolean positive) {
        Bundle feedback = new Bundle();
        feedback.putInt(FEEDBACK_RATING, positive ? 1 : -1);

        sendFeedbackToAssistant(feedback);
    }

    private void sendFeedbackToAssistant(Bundle feedback) {
        if (!mFeedbackController.isFeedbackEnabled()) {
            return;
        }

        try {
            mStatusBarService.onNotificationFeedbackReceived(mRanking.getKey(), feedback);
        } catch (RemoteException e) {
            if (DEBUG) {
                Log.e(TAG, "Failed to send feedback to assistant", e);
            }
        }
    }

    private void closeControls(View v) {
        mGutsContainer.closeControls(v, false);
    }

    @Override
    public void setGutsParent(NotificationGuts guts) {
        mGutsContainer = guts;
    }

    @Override
    public View getContentView() {
        return this;
    }

    @Override
    public int getActualHeight() {
        return getHeight();
    }

    @Override
    public boolean handleCloseControls(boolean save, boolean force) {
        return false;
    }

    @Override
    public boolean willBeRemoved() {
        return false;
    }

    @Override
    public boolean shouldBeSaved() {
        return false;
    }

    @Override
    public boolean needsFalsingProtection() {
        return false;
    }
}
