package com.atmob.keyboard_android.util.bridge.util

import android.os.Handler
import android.os.Looper
import com.atmob.keyboard_android.constant.PluginConfig
import com.atmob.keyboard_android.util.JsonUtil
import com.atmob.keyboard_android.util.LogUtil
import com.atmob.keyboard_android.util.bridge.model.base.CallResult
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

/**
 * Flutter方法调用者
 */
class FlutterMethodCaller {
    /**
     * 用于与 Flutter 端通信的 MethodChannel
     */
    private lateinit var mMethodChannel: MethodChannel

    /**
     * 主线程Handler，用于Flutter回调安卓端时，在主线程回调外部
     */
    private val mMainHandler = Handler(Looper.getMainLooper())

    /**
     * 初始化
     */
    fun init(engine: FlutterEngine) {
        mMethodChannel = MethodChannel(
            engine.dartExecutor.binaryMessenger,
            PluginConfig.FLUTTER_METHOD_CHANNEL_NAME
        )
    }

    /**
     * 调用Flutter方法
     *
     * @param methodName 方法名
     * @param modelClazz 方法返回值类型
     * @param isReturnJson 方法是否返回json格式
     * @param onSuccess 成功回调
     * @param onFail 失败回调
     */
    fun <T> callMethod(
        methodName: String,
        args: Any? = null,
        modelClazz: Class<T>,
        isReturnJson: Boolean = true,
        onSuccess: ((resultObj: T) -> Unit)? = null,
        onFail: ((errorCode: Int, errorMsg: String) -> Unit)? = null
    ) {
        mMethodChannel.invokeMethod(methodName, args, object : MethodChannel.Result {
            override fun success(result: Any?) {
                if (isReturnJson) {
                    val resultJson = result.toString()
                    try {
                        // 先尝试解析json，如果code不为0，就是失败
                        val result = JsonUtil.parseJsonByClass<CallResult>(
                            resultJson,
                            CallResult::class.java
                        )
                        if (result.code != 0) {
                            runOnUIThread {
                                onFail?.invoke(result.code, result.message)
                            }
                            return
                        }
                        // 成功
                        val resultObj = JsonUtil.parseJsonByClass<T>(resultJson, modelClazz)
                        runOnUIThread {
                            onSuccess?.invoke(resultObj)
                        }
                    } catch (e: Throwable) {
                        val errorMsg = e.message ?: "call error"
                        LogUtil.d("方法名：${methodName}，调用成功，但解析json失败，原因：${errorMsg}，json内容：${resultJson}")
                        runOnUIThread {
                            onFail?.invoke(-1, errorMsg)
                        }
                    }
                } else {
                    // 返回值，不是json，那么直接返回对象
                    runOnUIThread {
                        onSuccess?.invoke(result as T)
                    }
                }
            }

            override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
                val errorMsg = errorMessage ?: "call error"
                LogUtil.d("方法名：${methodName}，调用失败，原因：${errorMsg}")
                runOnUIThread {
                    onFail?.invoke(errorCode.toInt(), errorMsg)
                }
            }

            override fun notImplemented() {
                LogUtil.d("方法名：${methodName}，调用失败，Flutter未实现该方法")
                runOnUIThread {
                    onFail?.invoke(-1, "method not implemented")
                }
            }
        })
    }

    /**
     * 在主线程运行回调
     */
    private fun runOnUIThread(callback: () -> Unit) {
        // 如果已经在主线程了，直接回调
        if (Looper.getMainLooper().thread == Thread.currentThread()) {
            callback.invoke()
        } else {
            // 不在主线程，则切到主线程后，再回调
            mMainHandler.post {
                callback.invoke()
            }
        }
    }
}