package cc.winboll.studio.libappbase.utils;

import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;

import cc.winboll.studio.libappbase.CrashHandler;
import cc.winboll.studio.libappbase.GlobalCrashActivity;
import cc.winboll.studio.libappbase.LogUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 * @Date 2025/11/29 21:12
 * @Describe 应用崩溃处理通知实用工具集（类库兼容版）
 * 核心功能：作为独立类库使用，发送崩溃通知，点击跳转宿主应用的 GlobalCrashActivity 并传递日志
 * 适配说明：移除固定包名依赖，通过外部传入宿主包名，支持任意应用集成使用
 */
public class CrashHandleNotifyUtils {

    public static final String TAG = "CrashHandleNotifyUtils";

    /** 通知渠道ID（Android 8.0+ 必须） */
    private static final String CRASH_NOTIFY_CHANNEL_ID = "crash_notify_channel";
    /** 通知渠道名称（用户可见） */
    private static final String CRASH_NOTIFY_CHANNEL_NAME = "应用崩溃通知";
    /** 通知ID（唯一） */
    public static final int CRASH_NOTIFY_ID = 0x001;
    /** Android 12 对应 API 版本号（31） */
    private static final int API_LEVEL_ANDROID_12 = 31;
    /** PendingIntent.FLAG_IMMUTABLE 常量值（API 31+） */
    private static final int FLAG_IMMUTABLE = 0x00000040;

    /** 通知内容最大行数（控制在3行，超出部分省略） */
    private static final int NOTIFICATION_MAX_LINES = 3;


    /**
     * 处理未捕获异常（核心方法，类库入口）
     * 改进点：新增宿主包名参数，移除类库对固定包名的依赖
     * @param hostApp 宿主应用的 Application 实例（用于获取宿主上下文）
     * @param hostPackageName 宿主应用的包名（关键：用于绑定意图、匹配 Activity）
     * @param errorLog 崩溃日志（从宿主 CrashHandler 传递过来）
     */
    public static void handleUncaughtException(Application hostApp, String hostPackageName, String errorLog) {
        // 1. 校验核心参数（类库场景必须严格校验，避免空指针）
        if (hostApp == null || TextUtils.isEmpty(hostPackageName) || TextUtils.isEmpty(errorLog)) {
            LogUtils.e(TAG, "发送崩溃通知失败：参数为空（hostApp=" + hostApp + ", hostPackageName=" + hostPackageName + ", errorLog=" + errorLog + "）");
            return;
        }

        // 2. 获取宿主应用名称（使用宿主上下文，避免类库包名混淆）
        String hostAppName = getHostAppName(hostApp, hostPackageName);

        // 3. 发送崩溃通知到宿主通知栏（点击跳转宿主的 GlobalCrashActivity）
        sendCrashNotification(hostApp, hostPackageName, hostAppName, errorLog);
    }

    /**
     * 重载方法：兼容原有调用逻辑（避免宿主集成时改动过大）
     * 从 Intent 中提取崩溃日志和宿主包名，适配原有 CrashHandler 调用方式
     * @param hostApp 宿主应用的 Application 实例
     * @param intent 存储崩溃信息的意图（extra 中携带崩溃日志）
     */
    public static void handleUncaughtException(Application hostApp, Intent intent) {
        // 从意图中提取宿主包名（优先使用意图中携带的包名，无则用宿主 Application 包名）
        String hostPackageName = intent.getStringExtra("EXTRA_HOST_PACKAGE_NAME");
        if (TextUtils.isEmpty(hostPackageName)) {
            hostPackageName = hostApp.getPackageName();
            LogUtils.w(TAG, "意图中未携带宿主包名，使用 Application 包名：" + hostPackageName);
        }

        // 从意图中提取崩溃日志（与 CrashHandler.EXTRA_CRASH_INFO 保持一致）
        String errorLog = intent.getStringExtra(CrashHandler.EXTRA_CRASH_LOG);

        // 调用核心方法处理
        handleUncaughtException(hostApp, hostPackageName, errorLog);
    }

    /**
     * 获取宿主应用名称（类库场景适配：使用宿主包名获取，避免类库包名干扰）
     * @param hostContext 宿主应用的上下文（Application 实例）
     * @param hostPackageName 宿主应用的包名
     * @return 宿主应用名称（读取失败返回 "未知应用"）
     */
    private static String getHostAppName(Context hostContext, String hostPackageName) {
        try {
            // 用宿主包名获取宿主应用信息，确保获取的是宿主的应用名称（类库关键改进）
            return hostContext.getPackageManager().getApplicationLabel(
                hostContext.getPackageManager().getApplicationInfo(hostPackageName, 0)
            ).toString();
        } catch (Exception e) {
            LogUtils.e(TAG, "获取宿主应用名称失败（包名：" + hostPackageName + "）", e);
            return "未知应用";
        }
    }

    /**
     * 发送崩溃通知到宿主系统通知栏（类库兼容版）
     * 改进点：全程使用宿主上下文和宿主包名，避免类库包名依赖
     * @param hostContext 宿主应用的上下文（Application 实例）
     * @param hostPackageName 宿主应用的包名
     * @param hostAppName 宿主应用的名称（用于通知标题）
     * @param errorLog 崩溃日志（传递给宿主的 GlobalCrashActivity）
     */
    private static void sendCrashNotification(Context hostContext, String hostPackageName, String hostAppName, String errorLog) {
        // 1. 获取宿主的通知管理器（使用宿主上下文，确保通知归属宿主应用）
        NotificationManager notificationManager = (NotificationManager) hostContext.getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager == null) {
            LogUtils.e(TAG, "获取宿主 NotificationManager 失败（包名：" + hostPackageName + "）");
            return;
        }

        // 2. 适配 Android 8.0+（API 26+）：创建宿主的通知渠道（归属宿主，避免类库渠道冲突）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createCrashNotifyChannel(hostContext, notificationManager);
        }

        // 3. 构建通知意图（核心改进：绑定宿主包名，跳转宿主的 GlobalCrashActivity）
        PendingIntent jumpIntent = getGlobalCrashPendingIntent(hostContext, hostPackageName, errorLog);
        if (jumpIntent == null) {
            LogUtils.e(TAG, "构建跳转意图失败（宿主包名：" + hostPackageName + "）");
            return;
        }

        // 4. 构建通知实例（使用宿主上下文，确保通知资源归属宿主）
        Notification notification = buildNotification(hostContext, hostAppName, errorLog, jumpIntent);

        // 5. 发送通知（归属宿主应用，避免类库与宿主通知混淆）
        notificationManager.notify(CRASH_NOTIFY_ID, notification);
        LogUtils.d(TAG, "崩溃通知发送成功（宿主包名：" + hostPackageName + "，标题：" + hostAppName + "，日志长度：" + errorLog.length() + "字符）");
    }

    /**
     * 创建宿主应用的崩溃通知渠道（类库场景：渠道归属宿主，避免类库与宿主渠道冲突）
     * @param hostContext 宿主应用的上下文
     * @param notificationManager 宿主的通知管理器
     */
    private static void createCrashNotifyChannel(Context hostContext, NotificationManager notificationManager) {
        // 仅 Android 8.0+ 执行（避免低版本报错）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 构建通知渠道（归属宿主应用，描述明确类库用途）
            android.app.NotificationChannel channel = new android.app.NotificationChannel(
                CRASH_NOTIFY_CHANNEL_ID,
                CRASH_NOTIFY_CHANNEL_NAME,
                NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription("应用崩溃通知（由 WinBoLL Studio 类库提供，点击查看详情）");
            // 注册渠道到宿主的通知管理器，确保渠道归属宿主
            notificationManager.createNotificationChannel(channel);
            LogUtils.d(TAG, "宿主崩溃通知渠道创建成功（宿主包名：" + hostContext.getPackageName() + "，渠道ID：" + CRASH_NOTIFY_CHANNEL_ID + "）");
        }
    }

    /**
     * 核心改进：构建跳转宿主 GlobalCrashActivity 的意图（类库关键）
     * 1. 绑定宿主包名，确保类库能正确启动宿主的 Activity；
     * 2. 传递崩溃日志，与宿主 GlobalCrashActivity 日志接收逻辑匹配；
     * 3. 使用宿主上下文，避免类库上下文导致的适配问题。
     * @param hostContext 宿主应用的上下文
     * @param hostPackageName 宿主应用的包名
     * @param errorLog 崩溃日志（传递给宿主的 GlobalCrashActivity）
     * @return 跳转崩溃详情页的 PendingIntent
     */
    private static PendingIntent getGlobalCrashPendingIntent(Context hostContext, String hostPackageName, String errorLog) {
        try {
            // 1. 构建跳转宿主 GlobalCrashActivity 的显式意图（类库场景必须显式指定宿主包名）
            Intent crashIntent = new Intent(hostContext, GlobalCrashActivity.class);
            // 关键：绑定宿主包名，确保意图能正确匹配宿主的 Activity（避免类库包名干扰）
            crashIntent.setPackage(hostPackageName);
            // 传递崩溃日志（键：EXTRA_CRASH_INFO，与宿主 GlobalCrashActivity 完全匹配）
            crashIntent.putExtra(CrashHandler.EXTRA_CRASH_LOG, errorLog);
            // 设置意图标志：确保在宿主应用中正常启动，避免重复创建和任务栈混乱
            crashIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

            // 2. 构建 PendingIntent（使用宿主上下文，适配高版本）
            int flags = PendingIntent.FLAG_UPDATE_CURRENT;
            if (Build.VERSION.SDK_INT >= API_LEVEL_ANDROID_12) {
                flags |= FLAG_IMMUTABLE;
            }

            return PendingIntent.getActivity(
                hostContext,
                CRASH_NOTIFY_ID, // 用通知ID作为请求码，确保唯一（避免意图复用）
                crashIntent,
                flags
            );
        } catch (Exception e) {
            LogUtils.e(TAG, "构建跳转意图失败（宿主包名：" + hostPackageName + "）", e);
            return null;
        }
    }

    /**
     * 构建通知实例（类库兼容版）
     * 改进点：使用宿主上下文加载资源，确保通知样式适配宿主应用
     * @param hostContext 宿主应用的上下文
     * @param hostAppName 宿主应用的名称（通知标题）
     * @param errorLog 崩溃日志（通知内容）
     * @param jumpIntent 通知点击跳转意图（跳转宿主的 GlobalCrashActivity）
     * @return 构建完成的 Notification 对象
     */
    private static Notification buildNotification(Context hostContext, String hostAppName, String errorLog, PendingIntent jumpIntent) {
        // 兼容 Android 8.0+：指定宿主的通知渠道ID
        Notification.Builder builder = new Notification.Builder(hostContext);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(CRASH_NOTIFY_CHANNEL_ID);
        }

        // 核心：用BigTextStyle控制“默认3行省略，下拉显示完整”（使用宿主上下文构建）
        Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle();
        bigTextStyle.setSummaryText("日志已省略，下拉查看完整内容");
        bigTextStyle.bigText(errorLog);
        bigTextStyle.setBigContentTitle(hostAppName + " 崩溃"); // 标题明确标识宿主和崩溃状态
        builder.setStyle(bigTextStyle);

        // 配置通知核心参数（全程使用宿主上下文，确保资源归属宿主）
        builder
            // 关键：使用宿主应用的小图标（避免类库图标显示异常）
            .setSmallIcon(hostContext.getApplicationInfo().icon)
            .setContentTitle(hostAppName + " 崩溃")
            .setContentText(getShortContent(errorLog)) // 3行内缩略文本
            .setContentIntent(jumpIntent) // 点击跳转宿主的 GlobalCrashActivity
            .setAutoCancel(true) // 点击后自动关闭
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_DEFAULT);

        // 适配 Android 4.1+：确保在宿主应用中正常显示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return builder.build();
        } else {
            return builder.getNotification();
        }
    }

    /**
     * 辅助方法：截取日志文本，确保显示在3行内（通用逻辑，无包名依赖）
     * @param content 完整崩溃日志
     * @return 3行内的缩略文本
     */
    private static String getShortContent(String content) {
        if (content == null || content.isEmpty()) {
            return "无崩溃日志";
        }
        int maxLength = 80; // 估算3行字符数（可根据需求调整）
        return content.length() <= maxLength ? content : content.substring(0, maxLength) + "...";
    }

    /**
     * 释放资源（类库场景：空实现，避免宿主调用时报错，预留扩展）
     * @param hostContext 宿主应用的上下文（显式传入，避免类库上下文依赖）
     */
    public static void release(Context hostContext) {
        LogUtils.d(TAG, "CrashHandleNotifyUtils 资源释放完成（宿主包名：" + (hostContext != null ? hostContext.getPackageName() : "未知") + "）");
    }
}
