package com.stand.standapp

import android.content.Context
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import com.stand.standapp.R
import com.stand.standapp.utils.LogManager
import com.stand.standapp.printer.PrinterManager
import timber.log.Timber
import com.example.kingway.ptt.SendAtUtil
import org.json.JSONArray
import org.json.JSONObject

class AndroidInterface(private val activity: MainActivity) {

    private var isSpeaking = false
    private var lastSpeakTime = 0L
    private val MIN_SPEAK_DURATION = 200L

    /**
     * JS bridge 调度入口
     * @param method JS 调用的方法名
     * @param argsJson JSON 数组格式的参数
     * @return 返回值（JSON 字符串或空串）
     */
    fun dispatch(method: String, argsJson: String): String {
        return try {
            val args = if (argsJson.isNotEmpty()) JSONArray(argsJson) else JSONArray()
            when (method) {
                "pttSpeakPlay" -> { pttSpeakPlay(); "" }
                "pttGetLoginStatus" -> pttGetLoginStatus()
                "pttGetLoginId" -> pttGetLoginId()
                "pttGetCurrentGroup" -> pttGetCurrentGroup()
                "pttSpeakRelease" -> { pttSpeakRelease(); "" }
                "pttForceRelease" -> { pttForceRelease(); "" }
                "pttGetGroupInfo" -> { pttGetGroupInfo(); "" }
                "pttGetGroupMemberInfo" -> { pttGetGroupMemberInfo(args.optString(0, "")); "" }
                "simulatePttConflict" -> { simulatePttConflict(); "" }
                "pttSendAtCmd" -> { pttSendAtCmd(args.optString(0, "")); "" }
                "pttJumpGroup" -> { pttJumpGroup(args.optString(0, "")); "" }
                "getPrinterStatus" -> getPrinterStatus()
                "printText" -> {
                    printText(optStringOrNull(args, 0), args.optInt(1, 0), args.optInt(2, 0), args.optInt(3, 0)); ""
                }
                "printBarcode" -> {
                    printBarcode(optStringOrNull(args, 0), args.optInt(1, 0), args.optInt(2, 0), args.optInt(3, 0), args.optInt(4, 0), args.optInt(5, 0)); ""
                }
                "printQR" -> {
                    printQR(optStringOrNull(args, 0), args.optInt(1, 0), args.optInt(2, 0)); ""
                }
                "printImage" -> {
                    printImage(optStringOrNull(args, 0), args.optInt(1, 0), args.optInt(2, 0), args.optInt(3, 0)); ""
                }
                "printColumns" -> {
                    if (args.length() >= 8) {
                        printColumns(optStringOrNull(args, 0), args.optInt(1, 0), optStringOrNull(args, 2), args.optInt(3, 0),
                            optStringOrNull(args, 4), args.optInt(5, 0), optStringOrNull(args, 6), args.optInt(7, 0))
                    }
                    ""
                }
                "printColumnsWithHeight" -> {
                    if (args.length() >= 9) {
                        printColumnsWithHeight(optStringOrNull(args, 0), args.optInt(1, 0), optStringOrNull(args, 2), args.optInt(3, 0),
                            optStringOrNull(args, 4), args.optInt(5, 0), optStringOrNull(args, 6), args.optInt(7, 0), args.optInt(8, 0))
                    }
                    ""
                }
                "cutPaper" -> { cutPaper(args.optBoolean(0, false)); "" }
                "printTestPage" -> { printTestPage(); "" }
                "checkPaper" -> { checkPaper(); "" }
                "exportLogs" -> exportLogs()
                "uploadLogs" -> { uploadLogs(); "" }
                "printPage" -> { printPage(); "" }
                "printRawData" -> { printRawData(optStringOrNull(args, 0)); "" }
                "startUpdate" -> { startUpdate(optStringOrNull(args, 0)); "" }
                "exitApp" -> { exitApp(); "" }
                "getVersionName" -> getVersionName()
                "getAboutInfo" -> getAboutInfo()
                "saveMessage" -> { saveMessage(optStringOrNull(args, 0)); "" }
                "getMessages" -> getMessages()
                "clearMessages" -> { clearMessages(); "" }
                "onPageFinished" -> { onPageFinished(); "" }
                "showRestartDialog" -> { showRestartDialog(args.optString(0, ""), args.optString(1, "提示")); "" }
                "showJsonDialog" -> { showJsonDialog(args.optString(0, "")); "" }
                "getTempCallStatus" -> getTempCallStatus()
                "maximizeTempCall" -> { maximizeTempCall(); "" }
                else -> {
                    Timber.tag("Bridge").w("Unknown method: $method")
                    ""
                }
            }
        } catch (e: Exception) {
            Timber.tag("Bridge").e(e, "Dispatch error: $method")
            ""
        }
    }

    private fun optStringOrNull(args: JSONArray, index: Int): String? {
        return if (index < args.length() && !args.isNull(index)) args.getString(index) else null
    }

    fun pttSpeakPlay() {
        if (!isSpeaking) {
            isSpeaking = true
            lastSpeakTime = System.currentTimeMillis()
            SendAtUtil.speakPlay()
            Timber.tag("PTT").d("Speak Play")
            MainActivity.executeJs("updatePttTalkStatus(true)")
        } else {
            Timber.tag("PTT").w("Speak Play ignored: already speaking")
        }
    }

    fun pttGetLoginStatus(): String {
        return com.example.kingway.ptt.CallBackResolution.getPttLoginStatus()
    }

    fun pttGetLoginId(): String {
        return com.example.kingway.ptt.CallBackResolution.getPttLoginId()
    }

    fun pttGetCurrentGroup(): String {
        return try {
            val json = JSONObject()
            json.put("groupId", com.example.kingway.ptt.CallBackResolution.getCurrentGroupId())
            json.put("groupName", com.example.kingway.ptt.CallBackResolution.getCurrentGroupName())
            json.toString()
        } catch (e: Exception) {
            Timber.tag("PTT").e(e, "pttGetCurrentGroup failed")
            "{\"groupId\":\"\",\"groupName\":\"\"}"
        }
    }

    fun pttSpeakRelease() {
        Timber.tag("PTT").d("pttSpeakRelease called, isSpeaking=%s", isSpeaking)
        if (isSpeaking) {
            val now = System.currentTimeMillis()
            val duration = now - lastSpeakTime

            if (duration < MIN_SPEAK_DURATION) {
                val delay = MIN_SPEAK_DURATION - duration
                Timber.tag("PTT").d("Speak duration too short ($duration ms), delaying release by $delay ms")
                Handler(Looper.getMainLooper()).postDelayed({
                    realRelease()
                }, delay)
            } else {
                realRelease()
            }
        }
    }

    private fun realRelease() {
        if (isSpeaking) {
            isSpeaking = false
            SendAtUtil.speakRelease()
            Timber.tag("PTT").d("Real Speak Release")
            MainActivity.executeJs("updatePttTalkStatus(false)")
        } else {
            Timber.tag("PTT").w("realRelease skipped: already released")
        }
    }

    fun pttForceRelease() {
        val wasSpeaking = isSpeaking
        isSpeaking = false
        SendAtUtil.speakRelease()
        Timber.tag("PTT").d("Force Release (wasSpeaking=%s)", wasSpeaking)
    }

    fun pttGetGroupInfo() {
        Timber.tag("PTT").d("pttGetGroupInfo called")
        SendAtUtil.getGroupInfo()
    }

    fun pttGetGroupMemberInfo(gid: String) {
        Timber.tag("PTT").d("pttGetGroupMemberInfo: gid=%s", gid)
        SendAtUtil.getGroupMemberInfo(gid)
    }

    fun simulatePttConflict() {
        Timber.tag("PTT").w("simulatePttConflict: showing conflict dialog via JS bridge")
        Handler(Looper.getMainLooper()).post {
            MainActivity.showPttConflictDialog()
        }
    }

    fun pttSendAtCmd(cmd: String) {
        Timber.tag("PTT").d("pttSendAtCmd: %s", cmd)
        SendAtUtil.sendRawCmd(cmd)
    }

    fun pttJumpGroup(gid: String) {
        Timber.tag("PTT").d("pttJumpGroup: gid=%s", gid)
        SendAtUtil.jumpGroup(gid)
    }

    fun getPrinterStatus(): String {
        return try {
            val json = JSONObject()
            val connected = PrinterManager.isConnected()
            json.put("connected", connected)
            json.put("hasPaper", PrinterManager.isPaperReady())
            json.put("port", AppConfig.getSerialPort(activity))
            json.toString()
        } catch (e: Exception) {
            "{\"connected\":false, \"hasPaper\":false, \"error\":\"${e.message}\"}"
        }
    }

    fun printText(text: String?, size: Int, align: Int, space: Int) {
        if (text.isNullOrEmpty()) return
        try {
            PrinterManager.getFactory()?.let {
                if (it.isConnection) {
                    it.PrintText(text, size, align, space)
                }
            }
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printText failed")
        }
    }

    fun printBarcode(data: String?, size: Int, height: Int, align: Int, text_pos: Int, type: Int) {
        if (data.isNullOrEmpty()) return
        try {
            PrinterManager.getFactory()?.PrintBarcode(data, size, height, align, text_pos, type)
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printBarcode failed")
        }
    }

    fun printQR(data: String?, size: Int, l_m: Int) {
        if (data.isNullOrEmpty()) return
        try {
            PrinterManager.getFactory()?.PrintQR(data, size, l_m)
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printQR failed")
        }
    }

    fun printImage(fileName: String?, width: Int, align: Int, mode: Int) {
        if (fileName.isNullOrEmpty()) return
        try {
            val stream = activity.assets.open(fileName)
            val bitmap = android.graphics.BitmapFactory.decodeStream(stream)
            PrinterManager.getFactory()?.PrintImage(bitmap, width, align, mode)
            stream.close()
        } catch (e: Exception) {
            Timber.tag("JS_Interface").e(e, "printImage failed: $fileName")
        }
    }

    fun printColumns(c1: String?, p1: Int, c2: String?, p2: Int, c3: String?, p3: Int, c4: String?, p4: Int) {
        try {
            PrinterManager.getFactory()?.Printcolumncontent(c1 ?: "", p1, c2 ?: "", p2, c3 ?: "", p3, c4 ?: "", p4)
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printColumns failed")
        }
    }

    fun printColumnsWithHeight(c1: String?, p1: Int, c2: String?, p2: Int, c3: String?, p3: Int, c4: String?, p4: Int, height: Int) {
        try {
            PrinterManager.getFactory()?.Printcolumncontent(c1 ?: "", p1, c2 ?: "", p2, c3 ?: "", p3, c4 ?: "", p4, height)
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printColumnsWithHeight failed")
        }
    }

    fun cutPaper(allCut: Boolean) {
        try {
            if (allCut){
                PrinterManager.getFactory()?.PaperAllCut();
            }else{
                PrinterManager.getFactory()?.PaperCut();
            }
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "cutPaper failed")
        }
    }

    fun printTestPage() {
        try {
            PrinterManager.getFactory()?.PrintTestPage()
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "printTestPage failed")
        }
    }

    fun checkPaper() {
        try {
            PrinterManager.getFactory()?.Check_Paper()
        } catch (e: Throwable) {
            Timber.tag("JS_Interface").e(e, "checkPaper failed")
        }
    }

    fun exportLogs(): String {
        val zipPath = LogManager.zipLogs(activity)
        if (zipPath != null) {
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(activity.applicationContext, "日志已打包: $zipPath", Toast.LENGTH_LONG).show()
            }
            return zipPath
        } else {
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(activity.applicationContext, "暂无日志或打包失败", Toast.LENGTH_SHORT).show()
            }
            return ""
        }
    }

    fun uploadLogs() {
        LogManager.uploadLogs(activity) { success, message ->
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(activity.applicationContext, if (success) "日志上传成功" else "上传失败: $message", Toast.LENGTH_SHORT).show()
            }
        }
    }

    /**
     * 系统打印（GeckoView 不支持 WebView.createPrintDocumentAdapter）
     * 如需此功能，需用 GeckoSession 生成 PDF 后打印
     */
    fun printPage() {
        Handler(Looper.getMainLooper()).post {
            Toast.makeText(activity.applicationContext, "GeckoView 暂不支持系统打印，请使用热敏打印功能", Toast.LENGTH_SHORT).show()
        }
    }

    fun printRawData(data: String?) {
        if (data.isNullOrEmpty()) return
        try {
            Timber.tag("Print").d("收到 H5 原始打印数据: $data")
            Handler(Looper.getMainLooper()).post {
                try {
                    Toast.makeText(activity.applicationContext, "H5指令打印: $data", Toast.LENGTH_SHORT).show()
                } catch (e: Exception) {
                    Timber.tag("Print").e(e, "Toast显示失败")
                }
            }
        } catch (e: Exception) {
            Timber.tag("Print").e(e, "指令解析失败")
        }
    }

    fun startUpdate(apkUrl: String?) {
        Handler(Looper.getMainLooper()).post {
            try {
                UpdateManager(activity).checkUpdate()
            } catch (e: Exception) {
                Timber.tag("Update").e(e, "启动更新检查失败")
            }
        }
    }

    fun exitApp() {
        Handler(Looper.getMainLooper()).post {
            try {
                activity.showExitDialog()
            } catch (e: Exception) {
                Timber.tag("App").e(e, "显示退出弹窗失败")
                activity.finish()
            }
        }
    }

    fun getVersionName(): String {
        return try {
            val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
            packageInfo.versionName ?: "1.0.0"
        } catch (e: Exception) {
            Timber.tag("AndroidInterface").e(e, "getVersionName failed")
            "1.0.0"
        }
    }

    fun getAboutInfo(): String {
        return try {
            val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
            val json = JSONObject()
            json.put("appName", activity.getString(R.string.app_name))
            json.put("versionName", packageInfo.versionName)
            json.put("model", android.os.Build.MODEL)
            json.put("osVersion", android.os.Build.VERSION.RELEASE)

            val abis = android.os.Build.SUPPORTED_ABIS
            json.put("cpuAbi", abis.joinToString(","))

            val is64Bit = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                android.os.Process.is64Bit()
            } else {
                abis.any { it.contains("64") }
            }
            json.put("is64Bit", is64Bit)

            json.toString()
        } catch (e: Exception) {
            Timber.tag("AndroidInterface").e(e, "getAboutInfo failed")
            "{ \"appName\": \"消防值守台\", \"versionName\": \"1.0.0\" }"
        }
    }

    fun saveMessage(message: String?) {
        if (message.isNullOrEmpty()) return
        try {
            val prefs = activity.getSharedPreferences("msg_records", Context.MODE_PRIVATE)
            val currentMsgs = prefs.getString("history", "") ?: ""
            val updatedMsgs = if (currentMsgs.isEmpty()) message else "$message|---|$currentMsgs"
            val list = updatedMsgs.split("|---|").take(5000)
            prefs.edit().putString("history", list.joinToString("|---|")).apply()
        } catch (e: Exception) {
            Timber.tag("Storage").e(e, "消息保存异常")
        }
    }

    fun getMessages(): String {
        return try {
            val prefs = activity.getSharedPreferences("msg_records", Context.MODE_PRIVATE)
            prefs.getString("history", "") ?: ""
        } catch (e: Exception) {
            Timber.tag("Storage").e(e, "getMessages failed")
            ""
        }
    }

    fun clearMessages() {
        try {
            activity.getSharedPreferences("msg_records", Context.MODE_PRIVATE).edit().clear().apply()
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(activity.applicationContext, "记录已清空", Toast.LENGTH_SHORT).show()
            }
        } catch (e: Exception) {
            Timber.tag("Storage").e(e, "清空记录异常")
        }
    }

    fun onPageFinished() {
        Handler(Looper.getMainLooper()).post {
            try {
                activity.cancelTimeoutTimer()
                activity.findViewById<android.view.View>(R.id.loading_layout)?.visibility = android.view.View.GONE

                // 正式界面模式下，页面加载完成后传递登录数据给前端
                val isOfficial = activity.isOfficialMode()
                val data = activity.getLoginData()
                Timber.tag("AndroidInterface").d("onPageFinished: isOfficial=$isOfficial, data=$data")
                if (isOfficial && data.isNotEmpty()) {
                    val escaped = data.replace("'", "\\'").replace("\n", "\\n")
                    com.stand.standapp.MainActivity.executeJs("if(window.appLogin){window.appLogin('$escaped');}")
                    Timber.tag("AndroidInterface").d("Called appLogin")
                }
            } catch (e: Exception) {
                Timber.tag("UI").e(e, "隐藏加载布局失败")
            }
        }
    }

    fun showRestartDialog(message: String, title: String) {
        Timber.tag("AndroidInterface").w("showRestartDialog from JS: title=%s msg=%s", title, message)
        Handler(Looper.getMainLooper()).post {
            com.stand.standapp.MainActivity.showPttUpdateDialog(message, title)
        }
    }

    fun showJsonDialog(jsonStr: String) {
        Handler(Looper.getMainLooper()).post {
            try {
                val formatted = try {
                    val obj = org.json.JSONObject(jsonStr)
                    obj.toString(2)
                } catch (_: Exception) {
                    jsonStr
                }
                androidx.appcompat.app.AlertDialog.Builder(activity)
                    .setTitle("JSON 数据")
                    .setMessage(formatted)
                    .setPositiveButton("确认", null)
                    .show()
            } catch (e: Exception) {
                Timber.tag("UI").e(e, "showJsonDialog error")
            }
        }
    }

    fun getTempCallStatus(): String {
        return try {
            val json = JSONObject()
            json.put("isOpen", TempCallActivity.isOpen())
            json.put("isMinimized", TempCallActivity.isMinimizedState())
            json.toString()
        } catch (e: Exception) {
            "{\"isOpen\":false,\"isMinimized\":false}"
        }
    }

    fun maximizeTempCall() {
        Handler(Looper.getMainLooper()).post {
            try {
                TempCallActivity.maximize()
            } catch (e: Exception) {
                Timber.tag("TempCall").e(e, "maximizeTempCall error")
            }
        }
    }
}
