package com.wdkl.app.ncs.callingbed.helper;

import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.wdkl.app.ncs.callingbed.BuildConfig;
import com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity;
import com.wdkl.ncs.android.middleware.api.UrlManager;

import org.json.JSONObject;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import xcrash.ICrashCallback;
import xcrash.TombstoneManager;
import xcrash.TombstoneParser;
import xcrash.XCrash;

public class XCrashUtils {
    private final static String TAG = "XCrashUtils";

    private Application app;
    private OkHttpClient okHttpClient;

    // callback for java crash, native crash and ANR
    private final ICrashCallback callback = new ICrashCallback() {
        @Override
        public void onCrash(String logPath, String emergency) {
            Log.d(TAG, "log path: " + (logPath != null ? logPath : "(null)") + ", emergency: " + (emergency != null ? emergency : "(null)"));

            if (emergency != null) {
                debug(logPath, emergency);

                // Disk is exhausted, send crash report immediately.
                //sendThenDeleteCrashLog(logPath, emergency);
            } else {
                // Add some expanded sections. Send crash report at the next time APP startup.

                // OK
                TombstoneManager.appendSection(logPath, "expanded_key_1", "expanded_content");
                TombstoneManager.appendSection(logPath, "expanded_key_2", "expanded_content_row_1\nexpanded_content_row_2");

                // Invalid. (Do NOT include multiple consecutive newline characters ("\n\n") in the content string.)
                // TombstoneManager.appendSection(logPath, "expanded_key_3", "expanded_content_row_1\n\nexpanded_content_row_2");

                debug(logPath, null);
            }

            // Disk is exhausted, send crash report immediately.
            //sendThenDeleteCrashLog(logPath, emergency);

            //非debug版本上传crash日志
            if (!BuildConfig.DEBUG) {
                uploadCrashLog(logPath);
            } else {
                restartApp();
            }
        }
    };

    //ANR Catcher
    private final ICrashCallback anrCallback = new ICrashCallback() {
        @Override
        public void onCrash(String logPath, String emergency) {
            Log.d(TAG, "log path: " + (logPath != null ? logPath : "(null)") + ", emergency: " + (emergency != null ? emergency : "(null)"));

            if (emergency != null) {
                debug(logPath, emergency);

                // Disk is exhausted, send crash report immediately.
                //sendThenDeleteCrashLog(logPath, emergency);
            } else {
                // Add some expanded sections. Send crash report at the next time APP startup.

                // OK
                TombstoneManager.appendSection(logPath, "expanded_key_1", "expanded_content");
                TombstoneManager.appendSection(logPath, "expanded_key_2", "expanded_content_row_1\nexpanded_content_row_2");

                // Invalid. (Do NOT include multiple consecutive newline characters ("\n\n") in the content string.)
                // TombstoneManager.appendSection(logPath, "expanded_key_3", "expanded_content_row_1\n\nexpanded_content_row_2");

                debug(logPath, null);
            }

            AppUpdateHelper.reboot(app);
        }
    };

    public void init(Application application) {
        Log.d(TAG, "xCrash SDK init: start");
        app = application;

        // Initialize xCrash.
        XCrash.init(application, new XCrash.InitParameters()
                .setAppVersion(BuildConfig.VERSION_NAME)
                .setJavaRethrow(true)
                .setJavaLogCountMax(10)
                .setJavaDumpAllThreadsWhiteList(new String[]{"^main$", "^Binder:.*", ".*Finalizer.*"})
                .setJavaDumpAllThreadsCountMax(10)
                .setJavaCallback(callback)
                .setNativeRethrow(true)
                .setNativeLogCountMax(10)
                .setNativeDumpAllThreadsWhiteList(new String[]{"^xcrash\\.sample$", "^Signal Catcher$", "^Jit thread pool$", ".*(R|r)ender.*", ".*Chrome.*"})
                .setNativeDumpAllThreadsCountMax(10)
                .setNativeCallback(callback)
                .setAnrRethrow(true)
                .setAnrLogCountMax(10)
                .setAnrCallback(anrCallback)
                .setPlaceholderCountMax(3)
                .setPlaceholderSizeKb(512)
                .setLogDir(application.getExternalFilesDir("xcrash").toString())
                .setLogFileMaintainDelayMs(5000));
    }

    private void uploadCrashLog(String path) {
        final File logFile = new File(path);
        if (logFile.exists()) {
            final UrlManager urlManager = UrlManager.Companion.build();
            String url = urlManager.getBuyer() + "ncs/upload/file";
            HttpHelper.upload(url, logFile, new HttpHelper.UploadCallback() {
                @Override
                public void onFail() {
                    Log.e(TAG,"错误日志文件上传失败!");
                    restartApp();
                }

                @Override
                public void onSuccess(String data) {
                    Log.e(TAG,"错误日志文件上传成功!" + data);
                    sendThenDeleteCrashLog(urlManager.getBuyer() + data, null);
                    //删除日志文件
                    //logFile.delete();
                }
            });
        }
    }

    private void sendThenDeleteCrashLog(final String logPath, String emergency) {
        try {
            // Parse
            //Map<String, String> map = TombstoneParser.parse(logPath, emergency);
            //String crashReport = new JSONObject(map).toString();

            if(okHttpClient == null){
                okHttpClient = new OkHttpClient();
            }

            FormBody.Builder formBody = new FormBody.Builder();
            formBody.add("class_name", app.getPackageName());
            formBody.add("method_name", "");
            formBody.add("exception_name", "");
            formBody.add("err_msg", "");
            formBody.add("stack_trace", logPath);

            UrlManager urlManager = UrlManager.Companion.build();
            Request request  = new Request.Builder()
                    .url(urlManager.getBuyer() + "device/error_log")
                    .post(formBody.build())
                    .build();

            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG,"错误日志名称上传失败"+e.getMessage());
                    restartApp();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Log.d(TAG,"错误日志名称上传成功");
                    TombstoneManager.deleteTombstone(logPath);
                    //String data = response.body().string();
                    //Log.d(TAG,"错误日志数据 data "+data);
                    restartApp();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Send the crash report to server-side.
        // ......

        // If the server-side receives successfully, delete the log file.
        //
        // Note: When you use the placeholder file feature,
        //       please always use this method to delete tombstone files.
        //
        //TombstoneManager.deleteTombstone(logPath);
    }

    private void debug(String logPath, String emergency) {
        // Parse and save the crash info to a JSON file for debugging.
        FileWriter writer = null;
        try {
            File debug = new File(XCrash.getLogDir() + "/debug.json");
            debug.createNewFile();
            writer = new FileWriter(debug, false);
            writer.write(new JSONObject(TombstoneParser.parse(logPath, emergency)).toString());
        } catch (Exception e) {
            Log.d(TAG, "debug failed", e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (Exception ignored) {
                }
            }
        }
    }

    private void restartApp() {
        //重新启动app
        Intent mStartActivity = new Intent(app.getApplicationContext(), WelcomeActivity.class);
        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        int mPendingIntentId = 123456;
        PendingIntent mPendingIntent = PendingIntent.getActivity(app.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager mgr = (AlarmManager) app.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, mPendingIntent);

        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(0);
    }

}
