package candybar.lib.helpers;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.danimahardhika.android.helpers.core.utils.LogUtil;
import com.google.android.material.textfield.TextInputLayout;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import candybar.lib.R;
import candybar.lib.applications.CandyBarApplication;
import candybar.lib.items.Icon;
import candybar.lib.tasks.ReportBugsTask;

/*
 * CandyBar - Material Dashboard
 *
 * Copyright (c) 2014-2016 Dani Mahardhika
 *
 * 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.
 */

public class ReportBugsHelper {

    public static final String REPORT_BUGS = "reportbugs.zip";
    private static final String BROKEN_APPFILTER = "broken_appfilter.xml";
    private static final String BROKEN_DRAWABLES = "broken_drawables.xml";
    private static final String ACTIVITY_LIST = "activity_list.xml";
    private static final String CRASHLOG = "crashlog.txt";

    public static void prepareReportBugs(@NonNull Context context) {
        MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
        builder.customView(R.layout.dialog_report_bugs, true);
        builder.typeface(
                TypefaceHelper.getMedium(context),
                TypefaceHelper.getRegular(context));
        builder.positiveText(R.string.report_bugs_send);
        builder.negativeText(R.string.close);

        MaterialDialog dialog = builder.build();

        EditText editText = (EditText) dialog.findViewById(R.id.input_desc);
        TextInputLayout inputLayout = (TextInputLayout) dialog.findViewById(R.id.input_layout);

        dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(view -> {
            if (editText.getText().length() > 0) {
                inputLayout.setErrorEnabled(false);
                ReportBugsTask.start(context, editText.getText().toString(), AsyncTask.THREAD_POOL_EXECUTOR);
                dialog.dismiss();
                return;
            }

            inputLayout.setError(context.getResources().getString(R.string.report_bugs_desc_empty));
        });
        dialog.show();
    }

    @Nullable
    public static File buildBrokenAppFilter(@NonNull Context context) {
        try {
            HashMap<String, String> activities = RequestHelper.getAppFilter(context, RequestHelper.Key.ACTIVITY);
            File brokenAppFilter = new File(context.getCacheDir(), BROKEN_APPFILTER);
            Writer writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(brokenAppFilter), "UTF8"));

            boolean first = true;
            for (Map.Entry<String, String> entry : activities.entrySet()) {
                if (first) {
                    first = false;
                    writer.append("<!-- BROKEN APPFILTER -->")
                            .append("\n").append("<!-- Broken appfilter will check for activities that included in appfilter but doesn\'t have a drawable")
                            .append("\n").append("* ").append("The reason could because misnamed drawable or the drawable not copied to the project -->")
                            .append("\n\n\n");
                }

                int drawable = context.getResources().getIdentifier(
                        entry.getValue(), "drawable", context.getPackageName());
                if (drawable == 0) {
                    writer.append("Activity: ").append(entry.getKey())
                            .append("\n")
                            .append("Drawable: ").append(entry.getValue()).append(".png")
                            .append("\n\n");
                }
            }

            writer.flush();
            writer.close();
            return brokenAppFilter;
        } catch (Exception e) {
            LogUtil.e(Log.getStackTraceString(e));
            return null;
        }
    }

    @Nullable
    public static File buildBrokenDrawables(@NonNull Context context) {
        try {
            HashMap<String, String> drawables = RequestHelper.getAppFilter(context, RequestHelper.Key.DRAWABLE);
            List<Icon> iconList = IconsHelper.getIconsList(context);
            List<Icon> icons = new ArrayList<>();

            File brokenDrawables = new File(context.getCacheDir(), BROKEN_DRAWABLES);
            Writer writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(brokenDrawables), "UTF8"));

            for (Icon icon : iconList) {
                if (CandyBarApplication.getConfiguration().isShowTabAllIcons()) {
                    if (!icon.getTitle().equals(CandyBarApplication.getConfiguration().getTabAllIconsTitle())) {
                        icons.addAll(icon.getIcons());
                    }
                } else {
                    icons.addAll(icon.getIcons());
                }
            }

            boolean first = true;
            for (Icon icon : icons) {
                if (first) {
                    first = false;
                    writer.append("<!-- BROKEN DRAWABLES -->")
                            .append("\n").append("<!-- Broken drawables will read drawables that listed in drawable.xml")
                            .append("\n").append("* ").append("and try to match them with drawables that used in appfilter.xml")
                            .append("\n").append("* ").append("The reason could be drawable copied to the project but not used in appfilter.xml -->")
                            .append("\n\n\n");
                }

                String drawable = drawables.get(icon.getTitle());
                if (drawable == null || drawable.length() == 0) {
                    writer.append("Drawable: ").append(icon.getTitle()).append(".png")
                            .append("\n\n");
                }
            }

            writer.flush();
            writer.close();
            return brokenDrawables;
        } catch (Exception e) {
            LogUtil.e(Log.getStackTraceString(e));
            return null;
        }
    }

    @Nullable
    public static File buildActivityList(@NonNull Context context) {
        try {
            File activityList = new File(context.getCacheDir(), ACTIVITY_LIST);
            Writer out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(activityList), "UTF8"));

            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);

            List<ResolveInfo> appList = context.getPackageManager().queryIntentActivities(
                    intent, PackageManager.GET_RESOLVED_FILTER);
            try {
                Collections.sort(appList, new ResolveInfo.DisplayNameComparator(context.getPackageManager()));
            } catch (Exception ignored) {
            }

            boolean first = true;
            for (ResolveInfo app : appList) {

                if (first) {
                    first = false;
                    out.append("<!-- ACTIVITY LIST -->")
                            .append("\n").append("<!-- Activity list is a list that contains all activity from installed apps -->")
                            .append("\n\n\n");
                }

                String name = app.activityInfo.loadLabel(context.getPackageManager()).toString();
                String activity = app.activityInfo.packageName + "/" + app.activityInfo.name;
                out.append("<!-- ").append(name).append(" -->");
                out.append("\n").append(activity);
                out.append("\n\n");
            }

            out.flush();
            out.close();
            return activityList;
        } catch (Exception e) {
            LogUtil.e(Log.getStackTraceString(e));
            return null;
        }
    }

    @Nullable
    public static File buildCrashLog(@NonNull Context context, @NonNull String stackTrace) {
        try {
            if (stackTrace.length() == 0) return null;

            File crashLog = new File(context.getCacheDir(), CRASHLOG);
            String deviceInfo = DeviceHelper.getDeviceInfoForCrashReport(context);
            Writer out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(crashLog), "UTF8"));
            out.append(deviceInfo).append(stackTrace);
            out.flush();
            out.close();
            return crashLog;
        } catch (Exception e) {
            LogUtil.e(Log.getStackTraceString(e));
            return null;
        }
    }
}