package cc.winboll.studio.libappbase;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @Author 豆包&ZhanGSKen<zhangsken@qq.com>
 * @CreateTime 2026-05-11 13:28:00
 * @EditTime 2026-05-11 13:30:45
 * @Describe 应用崩溃保险丝单例管理类
 * 限制短时间内应用重复崩溃，通过分级熔断机制控制崩溃页面跳转策略；
 * 防护等级区间 1~2，每次崩溃自动降级，等级溢出则判定为彻底熔断；
 * 支持本地文件持久化等级、延迟自动恢复、手动重置防护等级能力。
 */
public final class GlobalAppCrashSafetyWire {

    /** 日志标识标签 */
    public static final String TAG = "GlobalAppCrashSafetyWire";
    /** 最低防护等级阈值 */
    private static final int _MINI = 1;
    /** 最高防护等级阈值 */
    private static final int _MAX = 2;

    /** 单例实例对象 */
    private static volatile GlobalAppCrashSafetyWire _AppCrashSafetyWire;
    /** 当前防护熔断等级 */
    private volatile Integer currentSafetyLevel;

    /**
     * 私有构造方法
     * 单例禁止外部实例化，初始化加载本地持久化防护等级
     */
    private GlobalAppCrashSafetyWire() {
        LogUtils.d(TAG, "构造方法执行：初始化崩溃保险丝实例");
        currentSafetyLevel = loadCurrentSafetyLevel();
    }

    /**
     * 获取单例对象
     * @return GlobalAppCrashSafetyWire 单例
     */
    public static synchronized GlobalAppCrashSafetyWire getInstance() {
        if (_AppCrashSafetyWire == null) {
            _AppCrashSafetyWire = new GlobalAppCrashSafetyWire();
        }
        return _AppCrashSafetyWire;
    }

    /**
     * 设置当前防护等级
     * @param currentSafetyLevel 待设置的防护等级
     */
    public void setCurrentSafetyLevel(final int currentSafetyLevel) {
        this.currentSafetyLevel = currentSafetyLevel;
        LogUtils.d(TAG, "setCurrentSafetyLevel：设置等级 = " + currentSafetyLevel);
    }

    /**
     * 获取当前内存中防护等级
     * @return 当前防护等级
     */
    public int getCurrentSafetyLevel() {
        return currentSafetyLevel;
    }

    /**
     * 保存防护等级到本地文件持久化
     * @param currentSafetyLevel 待保存防护等级
     */
    public void saveCurrentSafetyLevel(final int currentSafetyLevel) {
        LogUtils.d(TAG, "saveCurrentSafetyLevel：开始持久化等级 = " + currentSafetyLevel);
        this.currentSafetyLevel = currentSafetyLevel;

        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(CrashHandler._CrashCountFilePath));
            oos.writeInt(currentSafetyLevel);
            oos.flush();
            LogUtils.d(TAG, "saveCurrentSafetyLevel：写入文件成功，等级 = " + currentSafetyLevel);
        } catch (IOException e) {
            LogUtils.e(TAG, "saveCurrentSafetyLevel：写入文件异常", e);
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    LogUtils.e(TAG, "saveCurrentSafetyLevel：关闭流异常", e);
                }
            }
        }
    }

    /**
     * 从本地文件读取防护等级
     * @return 加载后的防护等级
     */
    public int loadCurrentSafetyLevel() {
        LogUtils.d(TAG, "loadCurrentSafetyLevel：加载本地防护等级");
        File file = new File(CrashHandler._CrashCountFilePath);

        if (!file.exists()) {
            currentSafetyLevel = _MAX;
            LogUtils.d(TAG, "loadCurrentSafetyLevel：文件不存在，初始化为最高等级 = " + _MAX);
            saveCurrentSafetyLevel(currentSafetyLevel);
            return currentSafetyLevel;
        }

        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(CrashHandler._CrashCountFilePath));
            currentSafetyLevel = ois.readInt();
            LogUtils.d(TAG, "loadCurrentSafetyLevel：读取文件成功，当前等级 = " + currentSafetyLevel);
        } catch (IOException e) {
            LogUtils.e(TAG, "loadCurrentSafetyLevel：读取文件异常", e);
            currentSafetyLevel = _MAX;
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    LogUtils.e(TAG, "loadCurrentSafetyLevel：关闭流异常", e);
                }
            }
        }
        return currentSafetyLevel;
    }

    /**
     * 执行一次保险丝熔断降级
     * @return 降级后是否仍在有效防护区间
     */
    boolean burnSafetyWire() {
        LogUtils.d(TAG, "burnSafetyWire：执行一次熔断降级");
        final int safeLevel = loadCurrentSafetyLevel();

        if (isSafetyWireWorking(safeLevel)) {
            saveCurrentSafetyLevel(safeLevel - 1);
            return isSafetyWireWorking(safeLevel - 1);
        }
        return false;
    }

    /**
     * 校验指定等级是否在有效防护区间
     * @param safetyLevel 待校验防护等级
     * @return true=防护有效 false=已熔断
     */
    boolean isSafetyWireWorking(final int safetyLevel) {
        LogUtils.d(TAG, "isSafetyWireWorking：校验等级 = " + safetyLevel);
        if (safetyLevel >= _MINI && safetyLevel <= _MAX) {
            LogUtils.d(TAG, "isSafetyWireWorking：等级在合法区间内");
            return true;
        }
        LogUtils.d(TAG, "isSafetyWireWorking：等级超出合法区间，已熔断");
        return false;
    }

    /**
     * 立即恢复防护等级为最高等级
     */
    void resumeToMaximumImmediately() {
        LogUtils.d(TAG, "resumeToMaximumImmediately：重置为最高防护等级");
        GlobalAppCrashSafetyWire.getInstance().saveCurrentSafetyLevel(_MAX);
    }

    /**
     * 关闭防护，设置为临界最低等级
     */
    void off() {
        LogUtils.d(TAG, "off：设置为临界最低防护等级");
        saveCurrentSafetyLevel(_MINI);
    }

    /**
     * 检查当前整体保险丝是否处于可用防护状态
     * @return true=防护正常 false=已熔断
     */
    boolean isAppCrashSafetyWireOK() {
        LogUtils.d(TAG, "isAppCrashSafetyWireOK：检测当前防护状态");
        currentSafetyLevel = loadCurrentSafetyLevel();
        return isSafetyWireWorking(currentSafetyLevel);
    }

    /**
     * 延迟异步检测并自动恢复防护等级
     * @param context 上下文对象
     */
    void postResumeCrashSafetyWireHandler(final Context context) {
        LogUtils.d(TAG, "postResumeCrashSafetyWireHandler：开启延迟自动恢复任务");
        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
				@Override
				public void run() {
					final int nextLevel = currentSafetyLevel - 1;
					if (!GlobalAppCrashSafetyWire.getInstance().isSafetyWireWorking(nextLevel)) {
						GlobalAppCrashSafetyWire.getInstance().resumeToMaximumImmediately();
						LogUtils.d(TAG, "postResumeCrashSafetyWireHandler：临近熔断，自动重置最高等级");
					}
				}
			}, 500);
    }

	public static void testGlobalAppCrashSafetyWire(Context context) {
		if (GlobalAppCrashSafetyWire.getInstance().isAppCrashSafetyWireOK()) {
			GlobalAppCrashSafetyWire.getInstance().burnSafetyWire();
			for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
				context.getString(i);
			}
		}
	}
}

