package com.ez.ertc;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Looper;
import android.widget.Toast;

import com.orhanobut.logger.Logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class CrashHandler implements Thread.UncaughtExceptionHandler {

    // 系统默认的UncaughtException处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    // CrashHandler实例
    @SuppressLint("StaticFieldLeak")
    private static CrashHandler INSTANCE;
    // 程序的Context对象
    private Context mContext;

    private OnCaughtExceptionListener onCaughtExceptionListener;

    private CrashHandler() {
    }

    /**
     * 获取CrashHandler实例 ,单例模式
     */
    public static CrashHandler getInstance() {
        if (INSTANCE == null){
            INSTANCE = new CrashHandler();
        }
        return INSTANCE;
    }

    /**
     * 初始化
     *
     * @param context
     */
    public void init(Context context) {
        mContext = context;
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    public void registerOnCaughtExceptionListener(OnCaughtExceptionListener onCaughtExceptionListener){
        this.onCaughtExceptionListener = onCaughtExceptionListener;
    }

    public void onException(Throwable ex){
        if (onCaughtExceptionListener != null){
            onCaughtExceptionListener.onException(ex);
        }
        writeToFile(ex,"crashlogcaught");
    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, final Throwable ex) {
        Logger.e(ex,ex.getMessage());
        // 使用Toast来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                writeToFile(ex,"crashlog");
                Toast.makeText(mContext, "很抱歉,程序出现异常即将退出.", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Logger.e(e.getMessage());
        }
        if (mDefaultHandler != null){
            // 让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        }
        // 退出程序
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    private void writeToFile(Throwable ex,String type){
        if (YsCoreSDK.getInstance().getContext() == null){
            return;
        }
        String fileName = YsCoreSDK.getInstance().getContext().getExternalFilesDir(type).getAbsolutePath() + File.separator + getNowTime("yyyyMMddHHmmss") + ".txt";
        if (ex == null) {
            return;
        }
        Writer info = new StringWriter();
        PrintWriter printWriter = new PrintWriter(info);
        ex.printStackTrace(printWriter);

        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }

        String result = info.toString();
        printWriter.close();

        FileOutputStream trace = null;
        File file = new File(fileName);
        try {
            trace = new FileOutputStream(file);
            trace.write(result.getBytes());
            trace.flush();
            trace.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getNowTime(String pattern) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
            return sdf.format(new Date());
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 主要用于切面拦截onClick后造成的异常捕获
     */
    public interface OnCaughtExceptionListener {
        /**
         * 手动让bugly上报这个异常
         * @param ex
         */
        void onException(Throwable ex);
    }

}
