package com.narutohuo.xindazhou.push.impl

import android.content.Context
import android.os.Handler
import android.os.Looper
import cn.jpush.android.api.JPushInterface
import com.narutohuo.xindazhou.core.log.ILog
import com.narutohuo.xindazhou.core.push.IPushService
import com.narutohuo.xindazhou.push.api.PushService
import com.narutohuo.xindazhou.push.model.PushMessage

/**
 * 推送服务实现类（单例模式）
 * 
 * 推送服务是全局唯一的，整个应用只需要一个推送服务实例
 * 
 * 封装极光推送 SDK，提供统一的推送服务接口
 * 
 * 注意：不使用 ARouter 管理，直接通过单例模式提供实例
 */
class PushServiceImpl private constructor() : IPushService, PushService {
    
    companion object {
        @Volatile
        private var INSTANCE: PushServiceImpl? = null
        
        /**
         * 获取推送服务单例
         */
        @JvmStatic
        fun getInstance(): PushServiceImpl {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: PushServiceImpl().also { INSTANCE = it }
            }
        }
        
        /**
         * 销毁单例（用于测试或需要重新初始化时）
         */
        @JvmStatic
        fun destroyInstance() {
            INSTANCE?.unregister()
            INSTANCE = null
        }
    }
    
    private val tag = "PushService"
    private var applicationContext: Context? = null
    private var messageListener: ((PushMessage) -> Unit)? = null
    private var notificationClickListener: ((PushMessage) -> Unit)? = null
    /**
     * 页面映射规则：页面名称 -> Activity Class
     * 用于自动跳转，参考极光推送的跳转机制
     */
    private val pageMapping = mutableMapOf<String, Class<*>>()
    private var sequence = 0
    private val mainHandler = Handler(Looper.getMainLooper())
    private var isInitialized = false
    
    // 回调监听器
    private var registerListener: ((String) -> Unit)? = null
    private var connectedListener: ((Boolean) -> Unit)? = null
    private var tagOperatorListener: ((Boolean, Int, Set<String>?) -> Unit)? = null
    private var aliasOperatorListener: ((Boolean, Int, String?) -> Unit)? = null
    private var mobileNumberOperatorListener: ((Boolean, Int, String?) -> Unit)? = null
    
    // ========== IPushService 接口实现（适配层） ==========
    
    override fun initialize(context: Context, appKey: String, channel: String, debugMode: Boolean) {
        // 适配 IPushService 接口，直接调用初始化
        initialize(context)
    }
    
    override fun setMessageListener(listener: (String, String, Map<String, String>, String?) -> Unit) {
        // 适配 IPushService 接口，将基本类型回调转换为 PushMessage 回调
        // 直接设置内部变量，避免递归调用
        this.messageListener = { message ->
            listener(message.title, message.content, message.extras, message.messageId)
        }
        ILog.d(tag, "设置消息监听器（IPushService）")
    }
    
    override fun setNotificationClickListener(listener: ((String, String, Map<String, String>, String?) -> Unit)?) {
        // 适配 IPushService 接口，将基本类型回调转换为 PushMessage 回调
        // 直接设置内部变量，避免递归调用
        this.notificationClickListener = listener?.let { callback ->
            { message ->
                callback(message.title, message.content, message.extras, message.messageId)
            }
        }
        ILog.d(tag, if (listener != null) "设置通知点击监听器（IPushService）" else "清除通知点击监听器（IPushService）")
    }
    
    // ========== PushService 接口实现（原有接口） ==========
    
    override fun initialize(context: Context) {
        if (isInitialized) {
            ILog.w(tag, "推送服务已经初始化，跳过重复初始化")
            return
        }
        
        this.applicationContext = context.applicationContext
        
        // 使用 Android Log 直接输出，确保能看到日志
        android.util.Log.d(tag, "========== 开始初始化极光推送SDK ==========")
        ILog.d(tag, "初始化极光推送SDK")
        
        try {
            // 初始化极光推送（同步调用，但通常很快，不会阻塞主线程太久）
            // AppKey 从 AndroidManifest.xml 中的 meta-data 自动读取
            android.util.Log.d(tag, "调用 JPushInterface.init()...")
            JPushInterface.init(context.applicationContext)
            android.util.Log.d(tag, "JPushInterface.init() 调用完成")
            
            // 设置调试模式（开发环境启用，生产环境关闭）
            try {
                val buildConfigClass = Class.forName("${context.packageName}.BuildConfig")
                val debugField = buildConfigClass.getField("DEBUG")
                val isDebug = debugField.getBoolean(null)
                JPushInterface.setDebugMode(isDebug)
                android.util.Log.d(tag, "极光推送调试模式: $isDebug")
                ILog.d(tag, "极光推送调试模式: $isDebug")
            } catch (e: Exception) {
                // 获取 BuildConfig 失败，默认关闭调试模式
                JPushInterface.setDebugMode(false)
                android.util.Log.w(tag, "无法获取 BuildConfig.DEBUG，默认关闭调试模式")
                ILog.w(tag, "无法获取 BuildConfig.DEBUG，默认关闭调试模式")
            }
            
            isInitialized = true
            android.util.Log.d(tag, "========== 极光推送初始化成功 ==========")
            ILog.d(tag, "极光推送初始化成功")
        } catch (e: Exception) {
            // 初始化失败不应该影响应用启动，只记录日志
            // 推送功能将不可用，但应用可以正常运行
            android.util.Log.e(tag, "========== 极光推送初始化失败 ==========", e)
            android.util.Log.e(tag, "错误信息: ${e.message}")
            e.printStackTrace()
            ILog.e(tag, "极光推送初始化失败，推送功能将不可用", e)
            // 不抛出异常，允许应用继续运行
        }
    }
    
    override fun setAlias(alias: String) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化，请先调用 initialize()")
            return
        }
        
        ILog.d(tag, "setAlias: $alias")
        
        try {
            // 设置别名（用于推送）
            // sequence: 请求序列号，用于回调时识别请求
            JPushInterface.setAlias(ctx, sequence++, alias)
        } catch (e: Exception) {
            ILog.e(tag, "设置别名失败", e)
        }
    }
    
    override fun setTags(tags: List<String>) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化，请先调用 initialize()")
            return
        }
        
        ILog.d(tag, "setTags: $tags")
        
        try {
            // 设置标签（用于推送）
            // 将 List<String> 转换为 Set<String>
            JPushInterface.setTags(ctx, sequence++, tags.toSet())
        } catch (e: Exception) {
            ILog.e(tag, "设置标签失败", e)
        }
    }
    
    override fun setMessageListener(listener: (PushMessage) -> Unit) {
        this.messageListener = listener
        ILog.d(tag, "设置消息监听器")
        
        // 注意：极光推送的消息接收需要通过自定义的 BroadcastReceiver 来处理
        // 这里只是保存监听器，实际的消息接收需要在 Application 或 Activity 中
        // 通过自定义的 BroadcastReceiver 接收消息后，调用此监听器
    }
    
    override fun setNotificationClickListener(listener: ((PushMessage) -> Unit)?) {
        this.notificationClickListener = listener
        ILog.d(tag, if (listener != null) "设置通知点击监听器" else "清除通知点击监听器")
    }
    
    /**
     * 处理接收到的推送消息（由自定义 BroadcastReceiver 调用）
     */
    fun handleReceivedMessage(title: String, content: String, extras: Map<String, String>?, messageId: String?) {
        ILog.d(tag, "handleReceivedMessage: title=$title, content=$content")
        
        val message = PushMessage(
            title = title,
            content = content,
            extras = extras ?: emptyMap(),
            messageId = messageId,
            timestamp = System.currentTimeMillis()
        )
        
        // 在主线程中调用监听器
        mainHandler.post {
            messageListener?.invoke(message)
        }
    }
    
    /**
     * 设置页面映射规则（用于自动跳转）
     * 
     * @param page 页面名称（从推送的 extras["page"] 获取）
     * @param activityClass Activity Class
     */
    fun setPageMapping(page: String, activityClass: Class<*>) {
        pageMapping[page] = activityClass
        ILog.d(tag, "设置页面映射: $page -> ${activityClass.simpleName}")
    }
    
    /**
     * 设置多个页面映射规则
     * 
     * @param mappings 页面映射 Map
     */
    fun setPageMappings(mappings: Map<String, Class<*>>) {
        pageMapping.putAll(mappings)
        ILog.d(tag, "设置页面映射: ${mappings.size} 个")
    }
    
    /**
     * 处理通知点击事件（由自定义 BroadcastReceiver 调用）
     * 
     * 参考极光推送的跳转机制：
     * 1. 如果设置了页面映射，自动根据 extras["page"] 跳转
     * 2. 如果设置了 notificationClickListener，也会回调
     */
    fun handleNotificationClick(title: String, content: String, extras: Map<String, String>?, messageId: String?) {
        ILog.d(tag, "handleNotificationClick: title=$title, content=$content")
        
        val message = PushMessage(
            title = title,
            content = content,
            extras = extras ?: emptyMap(),
            messageId = messageId,
            timestamp = System.currentTimeMillis()
        )
        
        val ctx = applicationContext
        val extrasMap = extras ?: emptyMap()
        
        // 在主线程中处理
        mainHandler.post {
            // 1. 先尝试自动跳转（如果配置了页面映射）
            val page = extrasMap["page"]
            if (!page.isNullOrEmpty() && ctx != null) {
                val activityClass = pageMapping[page]
                
                if (activityClass != null) {
                    try {
                        val intent = android.content.Intent(ctx, activityClass)
                        // 将 extras 中的所有参数都传递给 Activity
                        extrasMap.forEach { (key, value) ->
                            intent.putExtra(key, value)
                        }
                        // 设置标志位，确保从通知栏点击可以启动 Activity
                        intent.flags = android.content.Intent.FLAG_ACTIVITY_NEW_TASK or android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
                        ctx.startActivity(intent)
                        ILog.d(tag, "自动跳转到页面: $page (${activityClass.simpleName})")
                    } catch (e: Exception) {
                        ILog.e(tag, "自动跳转失败: $page", e)
                    }
                } else {
                    ILog.w(tag, "未找到页面映射: $page，跳过自动跳转")
                }
            }
            
            // 2. 回调通知点击监听器（如果设置了）
            notificationClickListener?.invoke(message)
        }
    }
    
    override fun register() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化，请先调用 initialize()")
            return
        }
        
        android.util.Log.d(tag, "========== 开始注册推送服务 ==========")
        ILog.d(tag, "注册推送服务")
        
        try {
            // 检查并请求通知权限（Android 13+）
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
                val hasPermission = androidx.core.content.ContextCompat.checkSelfPermission(
                    ctx,
                    android.Manifest.permission.POST_NOTIFICATIONS
                ) == android.content.pm.PackageManager.PERMISSION_GRANTED
                
                if (!hasPermission) {
                    android.util.Log.w(tag, "⚠️⚠️⚠️ 通知权限未授予，推送可能无法显示通知 ⚠️⚠️⚠️")
                    ILog.w(tag, "通知权限未授予，推送可能无法显示通知")
                    ILog.w(tag, "请调用 isNotificationEnabled() 和 goToAppNotificationSettings() 引导用户授予权限")
                } else {
                    android.util.Log.d(tag, "✅ 通知权限已授予")
                    ILog.d(tag, "通知权限已授予")
                }
            }
            
            // 恢复推送（开启推送）
            android.util.Log.d(tag, "调用 JPushInterface.resumePush()...")
            JPushInterface.resumePush(ctx)
            android.util.Log.d(tag, "JPushInterface.resumePush() 调用完成")
            
            // JPush 注册是异步的，通常需要 2-5 秒才能完成
            // onRegister 回调会在注册成功后自动触发
            android.util.Log.w(tag, "JPush 注册是异步的，通常需要 2-5 秒")
            ILog.d(tag, "JPush 注册是异步的，请等待 onRegister 回调")
            
        } catch (e: Exception) {
            android.util.Log.e(tag, "========== 注册推送服务失败 ==========", e)
            android.util.Log.e(tag, "错误信息: ${e.message}")
            e.printStackTrace()
            ILog.e(tag, "注册推送服务失败", e)
        }
    }
    
    override fun unregister() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "注销推送服务")
        
        try {
            // 停止推送（关闭推送）
            JPushInterface.stopPush(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "注销推送服务失败", e)
        }
    }
    
    /**
     * 获取注册ID（用于标识设备）
     */
    override fun getRegistrationId(): String? {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return null
        }
        
        return try {
            JPushInterface.getRegistrationID(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "获取注册ID失败", e)
            null
        }
    }
    
    /**
     * 检查推送是否已开启
     * 
     * @return true 表示推送已开启，false 表示推送已停止或未初始化
     */
    override fun isPushEnabled(): Boolean {
        val ctx = applicationContext ?: return false
        
        return try {
            // isPushStopped() 返回 true 表示已停止，所以需要取反
            !JPushInterface.isPushStopped(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "检查推送状态失败", e)
            false
        }
    }
    
    // ========== 新增方法（参考案例） ==========
    
    /**
     * 检查通知权限是否开启
     * 
     * @return 1 表示开启，0 表示关闭，-1 表示检测失败
     */
    fun isNotificationEnabled(): Int {
        val ctx = applicationContext ?: return -1
        
        return try {
            JPushInterface.isNotificationEnabled(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "检查通知权限失败", e)
            -1
        }
    }
    
    /**
     * 跳转到应用的通知设置页面
     */
    fun goToAppNotificationSettings() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        try {
            JPushInterface.goToAppNotificationSettings(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "跳转到通知设置失败", e)
        }
    }
    
    /**
     * 恢复推送（开启推送）
     */
    fun resumePush() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "恢复推送")
        
        try {
            JPushInterface.resumePush(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "恢复推送失败", e)
        }
    }
    
    /**
     * 停止推送（关闭推送）
     */
    fun stopPush() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "停止推送")
        
        try {
            JPushInterface.stopPush(ctx)
        } catch (e: Exception) {
            ILog.e(tag, "停止推送失败", e)
        }
    }
    
    /**
     * 添加本地通知
     * 
     * @param title 通知标题
     * @param content 通知内容
     * @param extras 额外数据（可选）
     */
    fun addLocalNotification(title: String, content: String, extras: Map<String, Any>? = null) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        try {
            val ln = cn.jpush.android.data.JPushLocalNotification()
            ln.setBuilderId(0)
            ln.setTitle(title)
            ln.setContent(content)
            
            val notificationId = System.currentTimeMillis() / 1000
            ln.setNotificationId(notificationId)
            ln.setBroadcastTime(System.currentTimeMillis())
            
            // 设置 extras
            if (extras != null && extras.isNotEmpty()) {
                val jsonObject = org.json.JSONObject(extras)
                ln.setExtras(jsonObject.toString())
            }
            
            JPushInterface.addLocalNotification(ctx, ln)
            ILog.d(tag, "添加本地通知成功，notification_id=$notificationId")
        } catch (e: Exception) {
            ILog.e(tag, "添加本地通知失败", e)
        }
    }
    
    /**
     * 设置手机号（用于推送）
     * 
     * @param mobileNumber 手机号（格式：+86-1234567890 或 1234567890）
     */
    fun setMobileNumber(mobileNumber: String) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "setMobileNumber: $mobileNumber")
        
        try {
            JPushInterface.setMobileNumber(ctx, sequence++, mobileNumber)
        } catch (e: Exception) {
            ILog.e(tag, "设置手机号失败", e)
        }
    }
    
    /**
     * 删除标签
     * 
     * @param tags 要删除的标签列表
     */
    fun deleteTags(tags: List<String>) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "deleteTags: $tags")
        
        try {
            JPushInterface.deleteTags(ctx, sequence++, tags.toSet())
        } catch (e: Exception) {
            ILog.e(tag, "删除标签失败", e)
        }
    }
    
    /**
     * 清空所有标签
     */
    fun cleanTags() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "cleanTags")
        
        try {
            JPushInterface.cleanTags(ctx, sequence++)
        } catch (e: Exception) {
            ILog.e(tag, "清空标签失败", e)
        }
    }
    
    /**
     * 删除别名
     */
    fun deleteAlias() {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "deleteAlias")
        
        try {
            JPushInterface.deleteAlias(ctx, sequence++)
        } catch (e: Exception) {
            ILog.e(tag, "删除别名失败", e)
        }
    }
    
    /**
     * 检查标签绑定状态
     * 
     * @param tag 要检查的标签
     */
    fun checkTagBindState(tag: String) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            return
        }
        
        ILog.d(tag, "checkTagBindState: $tag")
        
        try {
            JPushInterface.checkTagBindState(ctx, sequence++, tag)
        } catch (e: Exception) {
            ILog.e(tag, "检查标签绑定状态失败", e)
        }
    }
    
    /**
     * 获取所有标签
     * 
     * @param callback 回调，参数为标签集合
     */
    fun getAllTags(callback: (Set<String>?) -> Unit) {
        val ctx = applicationContext ?: run {
            ILog.w(tag, "Context 未初始化")
            callback(null)
            return
        }
        
        ILog.d(tag, "getAllTags")
        
        try {
            JPushInterface.getAllTags(ctx, sequence++)
            // 结果会在 onTagOperatorResult 回调中返回
            // 这里临时保存 callback，在回调时调用
            // 注意：实际使用时需要用 sequence 来匹配请求和响应
        } catch (e: Exception) {
            ILog.e(tag, "获取所有标签失败", e)
            callback(null)
        }
    }
    
    // ========== 内部回调处理方法（由 JPushReceiver 调用） ==========
    
    /**
     * 处理注册成功回调
     */
    fun handleRegisterSuccess(registrationId: String) {
        ILog.d(tag, "注册成功: registrationId=$registrationId")
        mainHandler.post {
            registerListener?.invoke(registrationId)
        }
    }
    
    /**
     * 处理连接状态回调
     */
    fun handleConnectedStatus(isConnected: Boolean) {
        ILog.d(tag, "连接状态: isConnected=$isConnected")
        mainHandler.post {
            connectedListener?.invoke(isConnected)
        }
    }
    
    /**
     * 处理标签操作结果回调
     */
    fun handleTagOperatorResult(jPushMessage: cn.jpush.android.api.JPushMessage) {
        val isSuccess = jPushMessage.errorCode == 0
        val errorCode = jPushMessage.errorCode
        val tags = jPushMessage.tags
        
        ILog.d(tag, "标签操作结果: isSuccess=$isSuccess, errorCode=$errorCode, tags=$tags")
        
        mainHandler.post {
            tagOperatorListener?.invoke(isSuccess, errorCode, tags)
        }
    }
    
    /**
     * 处理检查标签结果回调
     */
    fun handleCheckTagOperatorResult(jPushMessage: cn.jpush.android.api.JPushMessage) {
        val isSuccess = jPushMessage.errorCode == 0
        val errorCode = jPushMessage.errorCode
        val checkTag = jPushMessage.checkTag
        val isBind = jPushMessage.tagCheckStateResult
        
        ILog.d(tag, "检查标签结果: isSuccess=$isSuccess, errorCode=$errorCode, checkTag=$checkTag, isBind=$isBind")
    }
    
    /**
     * 处理别名操作结果回调
     */
    fun handleAliasOperatorResult(jPushMessage: cn.jpush.android.api.JPushMessage) {
        val isSuccess = jPushMessage.errorCode == 0
        val errorCode = jPushMessage.errorCode
        val alias = jPushMessage.alias
        
        ILog.d(tag, "别名操作结果: isSuccess=$isSuccess, errorCode=$errorCode, alias=$alias")
        
        mainHandler.post {
            aliasOperatorListener?.invoke(isSuccess, errorCode, alias)
        }
    }
    
    /**
     * 处理手机号操作结果回调
     */
    fun handleMobileNumberOperatorResult(jPushMessage: cn.jpush.android.api.JPushMessage) {
        val isSuccess = jPushMessage.errorCode == 0
        val errorCode = jPushMessage.errorCode
        val mobileNumber = jPushMessage.mobileNumber
        
        ILog.d(tag, "手机号操作结果: isSuccess=$isSuccess, errorCode=$errorCode, mobileNumber=$mobileNumber")
        
        mainHandler.post {
            mobileNumberOperatorListener?.invoke(isSuccess, errorCode, mobileNumber)
        }
    }
    
    // ========== 设置回调监听器 ==========
    
    /**
     * 设置注册成功监听器
     */
    fun setRegisterListener(listener: ((String) -> Unit)?) {
        this.registerListener = listener
        ILog.d(tag, if (listener != null) "设置注册监听器" else "清除注册监听器")
    }
    
    /**
     * 设置连接状态监听器
     */
    fun setConnectedListener(listener: ((Boolean) -> Unit)?) {
        this.connectedListener = listener
        ILog.d(tag, if (listener != null) "设置连接监听器" else "清除连接监听器")
    }
    
    /**
     * 设置标签操作结果监听器
     */
    fun setTagOperatorListener(listener: ((Boolean, Int, Set<String>?) -> Unit)?) {
        this.tagOperatorListener = listener
        ILog.d(tag, if (listener != null) "设置标签操作监听器" else "清除标签操作监听器")
    }
    
    /**
     * 设置别名操作结果监听器
     */
    fun setAliasOperatorListener(listener: ((Boolean, Int, String?) -> Unit)?) {
        this.aliasOperatorListener = listener
        ILog.d(tag, if (listener != null) "设置别名操作监听器" else "清除别名操作监听器")
    }
    
    /**
     * 设置手机号操作结果监听器
     */
    fun setMobileNumberOperatorListener(listener: ((Boolean, Int, String?) -> Unit)?) {
        this.mobileNumberOperatorListener = listener
        ILog.d(tag, if (listener != null) "设置手机号操作监听器" else "清除手机号操作监听器")
    }
}

