/*
 * Copyright (C) 2018 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.permissioncontroller.incident;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.IncidentManager;
import android.provider.Settings;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.BulletSpan;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.activity.ComponentActivity;

import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.incident.wear.ConfirmationActivityWearViewHandler;

import java.util.ArrayList;

/**
 * Confirmation dialog for approving an incident or bug report for sharing off the device.
 */
public class ConfirmationActivity extends ComponentActivity implements OnClickListener,
        OnDismissListener {
    private static final String TAG = "ConfirmationActivity";

    /**
     * Currently displaying activity.
     */
    private static ConfirmationActivity sCurrentActivity;

    /**
     * Currently displaying uri.
     */
    private static Uri sCurrentUri;

    /**
     * If this activity is running in the current process, call finish() on it.
     */
    public static void finishCurrent() {
        if (sCurrentActivity != null) {
            sCurrentActivity.finish();
        }
    }

    /**
     * If the activity is in the resumed state, then record the Uri for the current
     * one, so PendingList can skip re-showing the same one.
     */
    public static Uri getCurrentUri() {
        return sCurrentUri;
    }

    /**
     * Create the activity.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Formatting formatting = new Formatting(this);

        final Uri uri = getIntent().getData();
        Log.d(TAG, "uri=" + uri);
        if (uri == null) {
            Log.w(TAG, "No uri in intent: " + getIntent());
            finish();
            return;
        }

        final IncidentManager.PendingReport pending = new IncidentManager.PendingReport(uri);
        final String appLabel = formatting.getAppLabel(pending.getRequestingPackage());

        final Resources res = getResources();

        ReportDetails details;
        try {
            details = ReportDetails.parseIncidentReport(this, uri);
        } catch (ReportDetails.ParseException ex) {
            Log.w("Rejecting report because it couldn't be parsed", ex);
            // If there was an error in the input we will just summarily reject the upload,
            // since we can't get proper approval. (Zero-length images or reasons means that
            // we will proceed with the imageless consent dialog).
            final IncidentManager incidentManager = getSystemService(IncidentManager.class);
            incidentManager.denyReport(uri);

            if (DeviceUtils.isWear(this)) {
                ConfirmationActivityWearViewHandler viewHandler =
                        new ConfirmationActivityWearViewHandler(this, incidentManager);
                setContentView(viewHandler.createView());
                viewHandler.updateViewModel(true, getString(R.string.incident_report_dialog_title),
                        getString(R.string.incident_report_error_dialog_text, appLabel), uri);
                return;
            }

            // Show a message to the user saying... nevermind.
            new AlertDialog.Builder(this)
                .setTitle(R.string.incident_report_dialog_title)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                finish();
                            }
                        })
                .setMessage(getString(R.string.incident_report_error_dialog_text, appLabel))
                .setOnDismissListener(this)
                .show();
            return;

        }

        final String message = getString(R.string.incident_report_dialog_text,
                appLabel,
                formatting.getDate(pending.getTimestamp()),
                formatting.getTime(pending.getTimestamp()),
                appLabel);

        if (DeviceUtils.isWear(this)) {
            ConfirmationActivityWearViewHandler viewHandler =
                    new ConfirmationActivityWearViewHandler(this,
                            getSystemService(IncidentManager.class));
            setContentView(viewHandler.createView());
            viewHandler.updateViewModel(false, getString(R.string.incident_report_dialog_title),
                    message, uri);
            return;
        }

        final View content = getLayoutInflater().inflate(R.layout.incident_confirmation,
                null);

        final ArrayList<String> reasons = details.getReasons();
        final int reasonsSize = reasons.size();
        if (reasonsSize > 0) {
            content.findViewById(R.id.reasonIntro).setVisibility(View.VISIBLE);

            final TextView reasonTextView = (TextView) content.findViewById(R.id.reasons);
            reasonTextView.setVisibility(View.VISIBLE);

            final int bulletSize =
                    (int) (res.getDimension(R.dimen.incident_reason_bullet_size) + 0.5f);
            final int bulletIndent =
                    (int) (res.getDimension(R.dimen.incident_reason_bullet_indent) + 0.5f);
            final int bulletColor =
                    getColor(R.color.incident_reason_bullet_color);

            final StringBuilder text = new StringBuilder();
            for (int i = 0; i < reasonsSize; i++) {
                text.append(reasons.get(i));
                if (i != reasonsSize - 1) {
                    text.append("\n");
                }
            }
            final SpannableString spannable = new SpannableString(text.toString());
            int spanStart = 0;
            for (int i = 0; i < reasonsSize; i++) {
                final int length = reasons.get(i).length();
                spannable.setSpan(new BulletSpan(bulletIndent, bulletColor, bulletSize),
                        spanStart, spanStart + length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                spanStart += length + 1;
            }

            reasonTextView.setText(spannable);
        }

        ((TextView) content.findViewById(R.id.message)).setText(message);

        final ArrayList<Drawable> images = details.getImages();
        final int imagesSize = images.size();
        if (imagesSize > 0) {
            content.findViewById(R.id.imageScrollView).setVisibility(View.VISIBLE);

            final LinearLayout imageList = (LinearLayout) content.findViewById(R.id.imageList);

            final int width = res.getDimensionPixelSize(R.dimen.incident_image_width);
            final int height = res.getDimensionPixelSize(R.dimen.incident_image_height);

            for (int i = 0; i < imagesSize; i++) {
                final ImageView imageView = new ImageView(this);
                imageView.setImageDrawable(images.get(i));
                imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

                imageList.addView(imageView, new LinearLayout.LayoutParams(width, height));
            }
        }

        final AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle(R.string.incident_report_dialog_title)
                .setPositiveButton(R.string.incident_report_dialog_allow_label, this)
                .setNegativeButton(R.string.incident_report_dialog_deny_label, this)
                .setOnDismissListener(this)
                .setView(content)
                .create();
        if (Settings.canDrawOverlays(this)) {
            final Window w = dialog.getWindow();
            if (SdkLevel.isAtLeastT()) {
                WindowManager.LayoutParams lpm = new WindowManager.LayoutParams();
                lpm.setSystemApplicationOverlay(true);
                w.setAttributes(lpm);
            }
            w.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
        }
        dialog.show();
    }

    /**
     * Activity lifecycle callback.  Now visible.
     */
    @Override
    protected void onStart() {
        super.onStart();
        sCurrentActivity = this;
        sCurrentUri = getIntent().getData();
    }

    /**
     * Activity lifecycle callback.  Now not visible.
     */
    @Override
    protected void onStop() {
        super.onStop();
        sCurrentActivity = null;
        sCurrentUri = null;
    }

    /**
     * Dialog canceled.
     */
    @Override
    public void onDismiss(DialogInterface dialog) {
        finish();
    }

    /**
     * Explicit button click.
     */
    @Override
    public void onClick(DialogInterface dialog, int which) {
        final IncidentManager incidentManager = getSystemService(IncidentManager.class);

        switch (which) {
            case DialogInterface.BUTTON_POSITIVE:
                incidentManager.approveReport(getIntent().getData());
                PendingList.getInstance().updateState(this, 0);
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                incidentManager.denyReport(getIntent().getData());
                PendingList.getInstance().updateState(this, 0);
                break;
        }
        finish();
    }
}
