package cc.winboll.studio.libappbase;

import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import cc.winboll.studio.libappbase.R;

/**
 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 * @Date 2025/11/11 19:58
 * @Describe 应用异常报告观察活动窗口类
 * 核心功能：应用发生未捕获崩溃时，由 CrashHandler 启动此页面，展示崩溃日志详情，
 * 并提供「复制日志」「重启应用」操作入口，便于开发者定位问题和用户恢复应用
 */
public final class GlobalCrashActivity extends Activity implements MenuItem.OnMenuItemClickListener {

    /** 日志标签（用于调试日志输出，唯一标识当前 Activity） */
    public static final String TAG = "GlobalCrashActivity";

    /** 菜单标识：复制崩溃日志（用于区分菜单项点击事件） */
    private static final int MENU_ITEM_COPY = 0;
    /** 菜单标识：重启应用（用于区分菜单项点击事件） */
    private static final int MENU_ITEM_RESTART = 1;

    /** 崩溃报告展示自定义视图 */
    // 负责渲染崩溃日志文本、提供 Toolbar 容器，封装了日志展示和菜单样式控制逻辑
    private GlobalCrashReportView mCrashReportView;

    /** 崩溃日志文本内容 */
    // 从 CrashHandler 通过 Intent 传递过来，包含异常堆栈、设备信息等完整崩溃数据
    private String mCrashLog;

    /**
     * Activity 创建时初始化（生命周期核心方法，仅执行一次）
     * @param savedInstanceState 保存的实例状态（崩溃页面无需恢复状态，此处仅作兼容）
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 初始化崩溃安全防护机制
        // 作用：防止应用重启后短时间内再次崩溃，由 CrashHandler 内部实现防护逻辑
        CrashHandler.AppCrashSafetyWire.getInstance()
			.postResumeCrashSafetyWireHandler(getApplicationContext());

        // 从 Intent 中获取崩溃日志数据（EXTRA_CRASH_INFO 为 CrashHandler 定义的常量键）
        mCrashLog = getIntent().getStringExtra(CrashHandler.EXTRA_CRASH_INFO);

        // 设置当前 Activity 的布局文件（展示崩溃报告的 UI 结构）
        setContentView(R.layout.activity_globalcrash);

        // 初始化崩溃报告展示视图（通过布局 ID 找到自定义 View 实例）
        mCrashReportView = findViewById(R.id.activityglobalcrashGlobalCrashReportView1);
        // 将崩溃日志设置到视图中，由自定义 View 负责排版和显示
        mCrashReportView.setReport(mCrashLog);

        // 设置页面的 ActionBar（复用自定义 View 中的 Toolbar 作为系统 ActionBar）
        setActionBar(mCrashReportView.getToolbar());

        // 配置 ActionBar 标题和副标题（非空判断避免空指针异常）
        if (getActionBar() != null) {
            // 设置标题：使用 CrashHandler 中定义的统一标题（如 "应用崩溃报告"）
            getActionBar().setTitle(CrashHandler.TITTLE);
            // 设置副标题：显示当前应用名称（从全局 Application 工具方法获取）
            getActionBar().setSubtitle(GlobalApplication.getAppName(getApplicationContext()));
        }
    }

    /**
     * 重写返回键点击事件
     * 逻辑：点击手机返回键时，直接重启应用（而非返回上一页，因崩溃后上一页状态可能异常）
     */
    @Override
    public void onBackPressed() {
        restartApp();
    }

    /**
     * 重启当前应用（核心工具方法）
     * 实现逻辑：
     * 1. 获取应用的启动意图（默认启动 AndroidManifest 中配置的主 Activity）
     * 2. 设置意图标志，清除原有任务栈，避免残留异常页面
     * 3. 启动主 Activity 并终止当前进程，确保应用完全重启
     */
    private void restartApp() {
        // 获取 PackageManager 实例（用于获取应用相关信息和意图）
        PackageManager packageManager = getPackageManager();
        // 获取应用的启动意图（参数为当前应用包名，返回主 Activity 的意图）
        Intent launchIntent = packageManager.getLaunchIntentForPackage(getPackageName());

        if (launchIntent != null) {
            // 设置意图标志：
            // FLAG_ACTIVITY_NEW_TASK：创建新的任务栈启动 Activity
            // FLAG_ACTIVITY_CLEAR_TOP：清除目标 Activity 之上的所有 Activity
            // FLAG_ACTIVITY_CLEAR_TASK：清除当前任务栈中的所有 Activity
            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
								  | Intent.FLAG_ACTIVITY_CLEAR_TOP
								  | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            // 启动应用主 Activity
            startActivity(launchIntent);
        }

        // 关闭当前崩溃报告页面
        finish();
        // 终止当前应用进程（确保释放所有资源，避免内存泄漏）
        android.os.Process.killProcess(android.os.Process.myPid());
        // 强制退出虚拟机（彻底终止应用，防止残留线程继续运行）
        System.exit(0);
    }

    /**
     * 菜单项点击事件回调（实现 MenuItem.OnMenuItemClickListener 接口）
     * @param item 被点击的菜单项实例
     * @return boolean：true 表示事件已消费，不再向下传递；false 表示未消费
     */
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        // 根据菜单项 ID 判断点击的是哪个功能
        switch (item.getItemId()) {
            case MENU_ITEM_COPY:
                // 点击「复制」菜单，执行复制崩溃日志到剪贴板
                copyCrashLogToClipboard();
                break;
            case MENU_ITEM_RESTART:
                // 点击「重启」菜单：先恢复崩溃防护机制到最大等级，再重启应用
                CrashHandler.AppCrashSafetyWire.getInstance().resumeToMaximumImmediately();
                restartApp();
                break;
        }
        return false;
    }

    /**
     * 创建页面顶部菜单（ActionBar 菜单）
     * @param menu 菜单容器，用于添加菜单项
     * @return boolean：true 表示显示菜单；false 表示不显示
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // 添加「复制」菜单项：
        // 参数说明：菜单组 ID（0 表示默认组）、菜单项 ID（MENU_ITEM_COPY）、排序号（0）、菜单文本（"Copy"）
        // setOnMenuItemClickListener(this)：绑定点击事件到当前 Activity
        // setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)：有空间时显示在 ActionBar 上，否则放入溢出菜单
        menu.add(0, MENU_ITEM_COPY, 0, "Copy")
			.setOnMenuItemClickListener(this)
			.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        // 添加「重启」菜单项（参数含义同上）
        menu.add(0, MENU_ITEM_RESTART, 0, "Restart")
			.setOnMenuItemClickListener(this)
			.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        // 调用自定义视图的方法，更新菜单文字样式（如颜色、字体大小等，由自定义 View 内部实现）
        mCrashReportView.updateMenuStyle();

        return true;
    }

    /**
     * 将崩溃日志复制到系统剪贴板（工具方法）
     * 功能：用户点击复制菜单后，将完整崩溃日志存入剪贴板，方便粘贴到聊天工具或文档中
     */
    private void copyCrashLogToClipboard() {
        // 获取系统剪贴板服务（需通过 getSystemService 方法获取）
        ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

        // 创建剪贴板数据：
        // 参数 1：标签（用于标识剪贴板内容来源，此处用应用包名）
        // 参数 2：实际复制的文本内容（崩溃日志）
        ClipData clipData = ClipData.newPlainText(getPackageName(), mCrashLog);

        // 将数据设置到剪贴板（完成复制操作）
        clipboardManager.setPrimaryClip(clipData);

        // 显示复制成功的 Toast 提示（告知用户操作结果）
        Toast.makeText(getApplication(), "The text is copied.", Toast.LENGTH_SHORT).show();
    }
}

