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.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.facade.template.IProvider
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.PushConfig
import com.narutohuo.xindazhou.push.model.PushMessage

/**
 * 推送服务实现类（单例模式）
 * 
 * 推送服务是全局唯一的，整个应用只需要一个推送服务实例
 * 
 * 封装极光推送 SDK，提供统一的推送服务接口
 * 
 * 通过 ARouter 注册，实现 base-core 与 push 模块的解耦
 */
@Route(path = "/push/service", name = "推送服务")
class PushServiceImpl private constructor() : IProvider, 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
    
    /**
     * ARouter IProvider 接口的初始化方法
     * 
     * 注意：此方法在 ARouter 初始化 provider 时调用，不应该抛出异常
     */
    override fun init(context: Context) {
        try {
            ILog.d(tag, "PushServiceImpl 初始化（ARouter）")
            // 这里不进行实际的初始化，实际的初始化在 PushServiceFactory.init() 中完成
            // 这样可以避免在 ARouter 初始化时出现问题
        } catch (e: Exception) {
            // 确保不会抛出异常，避免影响 ARouter 初始化
            ILog.e(tag, "PushServiceImpl ARouter 初始化异常（不影响使用）", e)
        }
    }
    
    // ========== IPushService 接口实现（适配层） ==========
    
    override fun initialize(context: Context, appKey: String, channel: String, debugMode: Boolean) {
        // 适配 IPushService 接口，将参数转换为 PushConfig
        val config = PushConfig(
            appKey = appKey,
            channel = channel,
            debugMode = debugMode
        )
        initialize(context, config)
    }
    
    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, config: PushConfig) {
        if (isInitialized) {
            ILog.w(tag, "推送服务已经初始化，跳过重复初始化")
            return
        }
        
        this.applicationContext = context.applicationContext
        ILog.d(tag, "初始化极光推送SDK")
        
        try {
            // 初始化极光推送（同步调用，但通常很快，不会阻塞主线程太久）
            JPushInterface.init(context.applicationContext)
            
            // 设置调试模式
            if (config.debugMode) {
                JPushInterface.setDebugMode(true)
                ILog.d(tag, "调试模式已开启")
            }
            
            isInitialized = true
            ILog.d(tag, "极光推送初始化成功, appKey=${config.appKey.take(8)}..., channel=${config.channel}")
        } catch (e: Exception) {
            // 初始化失败不应该影响应用启动，只记录日志
            // 推送功能将不可用，但应用可以正常运行
            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
        }
        
        ILog.d(tag, "注册推送服务")
        
        try {
            // 恢复推送（开启推送）
            JPushInterface.resumePush(ctx)
        } catch (e: Exception) {
            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
        }
    }
}

