package com.beancount.mobile.accessibility

import android.content.Context
import android.graphics.PixelFormat
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.graphics.drawable.GradientDrawable
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.Button
import android.widget.TextView
import android.widget.EditText
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.text.InputType
import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.modules.core.DeviceEventManagerModule
import java.math.BigDecimal

/**
 * 浮窗账单提示（直接呈现高度优化、支持三方向切换的修改入账面板）。
 * P6 重设计：颜色/文案走 FloatingUiConfigStore，新增币种 chip，金额校验改正则+BigDecimal。
 */
class FloatingBillView(
    private val context: Context,
    private val draftId: String,
    private val amount: String,
    private val merchant: String,
    private val time: String,
    private val packageName: String,
    private val categories: List<Map<String, String>> = emptyList(),
    private val accounts: List<String> = emptyList(),
    private val initialDirection: String = "expense",
    private val initialCurrency: String = "CNY"
) {
    companion object {
        private const val TAG = "FloatingBillView"
        private val DEFAULT_CURRENCY_LIST = listOf("CNY", "USD", "HKD", "JPY", "EUR", "GBP")
    }

    // 从 JS 下发的配置读取颜色与文案（缺失字段回退默认值，保证旧 JS 行为不变）
    private val config = FloatingUiConfigStore.load(context)

    // 显示币种列表；若 initialCurrency 不在默认列表中则临时插入首位
    private val currencyList: List<String> = run {
        val list = DEFAULT_CURRENCY_LIST.toMutableList()
        if (!list.contains(initialCurrency)) {
            list.add(0, initialCurrency)
        }
        list
    }
    private var currentCurrency: String = initialCurrency

    private val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    private var view: View? = null
    private val handler = Handler(Looper.getMainLooper())
    private var selectedCategoryAccount: String = ""
    private var selectedSourceAccount: String = ""
    private var currentDirection: String = "expense"

    private var categoryLabel: TextView? = null
    private var categoryContainer: LinearLayout? = null
    private var accountLabel: TextView? = null
    private var accountContainer: LinearLayout? = null
    private var saveBtn: Button? = null

    // 预解析常用颜色（parseColorOr 异常时回退默认值）
    private val colorAccent = FloatingUiConfigStore.parseColorOr(config.colors.accent, "#FF5E6AD2")
    private val colorAccentFg = FloatingUiConfigStore.parseColorOr(config.colors.accentFg, "#FFFFFFFF")
    private val colorCardBg = FloatingUiConfigStore.parseColorOr(config.colors.cardBg, "#F0050506")
    private val colorInputBg = FloatingUiConfigStore.parseColorOr(config.colors.inputBg, "#4012131A")
    private val colorFgPrimary = FloatingUiConfigStore.parseColorOr(config.colors.fgPrimary, "#FFFFFFFF")
    private val colorFgSecondary = FloatingUiConfigStore.parseColorOr(config.colors.fgSecondary, "#FF9CA3AF")
    private val colorBorder = FloatingUiConfigStore.parseColorOr(config.colors.border, "#80222433")
    private val colorIncome = FloatingUiConfigStore.parseColorOr(config.colors.income, "#FF10B981")
    private val colorExpense = FloatingUiConfigStore.parseColorOr(config.colors.expense, "#FFE11D48")
    private val colorTransfer = FloatingUiConfigStore.parseColorOr(config.colors.transfer, "#FF10B981")

    // 容器边框直接使用 config border（不再从 accent 派生 alpha）

    private fun dp(value: Float): Int {
        val density = context.resources.displayMetrics.density
        return (value * density).toInt()
    }

    private fun createChipView(text: String): TextView {
        return TextView(context).apply {
            this.text = text
            textSize = 11f
            setPadding(dp(8f), dp(4f), dp(8f), dp(4f))
            layoutParams = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            ).apply {
                rightMargin = dp(6f)
            }
        }
    }

    /** 显示悬浮窗。 */
    fun show() {
        try {
            currentDirection = if (initialDirection == "income" || initialDirection == "transfer") initialDirection else "expense"

            // 1. 设置 Window 布局参数使其可聚焦（用以键盘输入）并贴靠屏幕底部
            val overlayType = if (context is android.accessibilityservice.AccessibilityService) {
                WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
            } else {
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            }
            val windowParams = WindowManager.LayoutParams(
                dp(310f),
                WindowManager.LayoutParams.WRAP_CONTENT,
                overlayType,
                0, // 0 标志代表可获取焦点
                PixelFormat.TRANSLUCENT
            ).apply {
                gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
                y = dp(48f) // 留出底部导航栏空间 + 按钮/键盘安全区
            }

            // 2. 实色卡片背景（不再半透明磨砂），圆角 16dp，1dp 描边
            val containerBg = GradientDrawable().apply {
                shape = GradientDrawable.RECTANGLE
                cornerRadius = dp(16f).toFloat()
                setColor(colorCardBg)
                setStroke(dp(1f), colorBorder)  // 使用 config border 颜色
            }

            val container = LinearLayout(context).apply {
                orientation = LinearLayout.VERTICAL
                background = containerBg
                setPadding(dp(16f), dp(16f), dp(16f), dp(16f))
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }

            // 顶部标题与方向选择器布局
            val headerLayout = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
                gravity = Gravity.CENTER_VERTICAL
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }

            val titleText = TextView(context).apply {
                text = config.labels.billTitle
                textSize = 13f
                setTextColor(colorFgPrimary)
                paint.isFakeBoldText = true
                layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
            }
            headerLayout.addView(titleText)

            // 三方向分段选择器 (支出 / 收入 / 转账)
            val segmentContainer = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
                background = GradientDrawable().apply {
                    cornerRadius = dp(6f).toFloat()
                    setColor((colorFgPrimary and 0x00FFFFFF) or 0x12000000) // 7% fg overlay
                }
            }

            val tabTexts = listOf(config.labels.dirExpense, config.labels.dirIncome, config.labels.dirTransfer)
            val tabDirections = listOf("expense", "income", "transfer")
            val tabViews = mutableListOf<TextView>()

            fun updateTabStyle() {
                for (i in tabViews.indices) {
                    val active = tabDirections[i] == currentDirection
                    tabViews[i].apply {
                        setTextColor(if (active) colorAccentFg else colorFgSecondary)
                        background = if (active) {
                            GradientDrawable().apply {
                                cornerRadius = dp(6f).toFloat()
                                setColor(colorAccent)
                            }
                        } else {
                            null
                        }
                    }
                }
            }

            for (i in tabTexts.indices) {
                val tab = TextView(context).apply {
                    text = tabTexts[i]
                    textSize = 10f
                    setPadding(dp(6f), dp(3f), dp(6f), dp(3f))
                    gravity = Gravity.CENTER
                    setOnClickListener {
                        if (currentDirection != tabDirections[i]) {
                            currentDirection = tabDirections[i]
                            updateTabStyle()
                            rebuildChips()
                        }
                    }
                }
                segmentContainer.addView(tab)
                tabViews.add(tab)
            }
            updateTabStyle()
            headerLayout.addView(segmentContainer)
            container.addView(headerLayout)

            // 金额行：币种 chip（左）+ 金额输入框（右）
            val amountLabel = TextView(context).apply {
                text = config.labels.amountLabel
                textSize = 10f
                paint.isFakeBoldText = true
                setTextColor(colorFgSecondary)
                setPadding(0, dp(8f), 0, dp(1f))
            }
            container.addView(amountLabel)

            val amountRow = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
                gravity = Gravity.CENTER_VERTICAL
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }

            // 币种 chip
            val currencyChip = TextView(context).apply {
                text = currentCurrency
                textSize = 11f
                setTextColor(colorFgSecondary)
                setPadding(dp(8f), dp(4f), dp(8f), dp(4f))
                gravity = Gravity.CENTER
                background = GradientDrawable().apply {
                    shape = GradientDrawable.RECTANGLE
                    cornerRadius = dp(12f).toFloat()
                    setColor(colorInputBg)
                    setStroke(dp(1f), colorBorder)
                }
                setOnClickListener {
                    val idx = currencyList.indexOf(currentCurrency)
                    currentCurrency = currencyList[(idx + 1) % currencyList.size]
                    text = currentCurrency
                }
            }
            amountRow.addView(currencyChip)

            val amountInput = EditText(context).apply {
                textSize = 13f
                setTextColor(colorFgPrimary)
                setHintTextColor(colorFgSecondary)
                background = GradientDrawable().apply {
                    setColor(colorInputBg)
                    cornerRadius = dp(10f).toFloat()
                    setStroke(dp(1f), colorBorder)
                }
                setPadding(dp(10f), dp(6f), dp(10f), dp(6f))
                inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
                layoutParams = LinearLayout.LayoutParams(
                    0,
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    1f
                ).apply {
                    leftMargin = dp(8f)
                }
            }
            amountRow.addView(amountInput)
            container.addView(amountRow)
            container.addView(View(context).apply { layoutParams = LinearLayout.LayoutParams(1, dp(4f)) })

            // 商户编辑
            val merchantLabel = TextView(context).apply {
                text = config.labels.payeeLabel
                textSize = 10f
                paint.isFakeBoldText = true
                setTextColor(colorFgSecondary)
                setPadding(0, 0, 0, dp(1f))
            }
            container.addView(merchantLabel)

            val merchantInput = EditText(context).apply {
                setText(merchant)
                textSize = 12f
                setTextColor(colorFgPrimary)
                setHintTextColor(colorFgSecondary)
                background = GradientDrawable().apply {
                    setColor(colorInputBg)
                    cornerRadius = dp(10f).toFloat()
                    setStroke(dp(1f), colorBorder)
                }
                setPadding(dp(10f), dp(6f), dp(10f), dp(6f))
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }
            container.addView(merchantInput)
            container.addView(View(context).apply { layoutParams = LinearLayout.LayoutParams(1, dp(4f)) })

            // 叙述备注编辑
            val narrationLabel = TextView(context).apply {
                text = config.labels.narrationLabel
                textSize = 10f
                paint.isFakeBoldText = true
                setTextColor(colorFgSecondary)
                setPadding(0, 0, 0, dp(1f))
            }
            container.addView(narrationLabel)

            val narrationInput = EditText(context).apply {
                hint = config.labels.narrationHint
                setHintTextColor(colorFgSecondary)
                textSize = 12f
                setTextColor(colorFgPrimary)
                background = GradientDrawable().apply {
                    setColor(colorInputBg)
                    cornerRadius = dp(10f).toFloat()
                    setStroke(dp(1f), colorBorder)
                }
                setPadding(dp(10f), dp(6f), dp(10f), dp(6f))
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }
            container.addView(narrationInput)
            container.addView(View(context).apply { layoutParams = LinearLayout.LayoutParams(1, dp(6f)) })

            // Row 1 分类/转入选择
            categoryLabel = TextView(context).apply {
                text = config.labels.categoryExpense
                textSize = 10f
                paint.isFakeBoldText = true
                setTextColor(colorFgSecondary)
                setPadding(0, 0, 0, dp(2f))
            }
            container.addView(categoryLabel)

            categoryContainer = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
            }

            val categoryScroll = HorizontalScrollView(context).apply {
                isHorizontalScrollBarEnabled = false
                addView(categoryContainer)
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }
            container.addView(categoryScroll)
            container.addView(View(context).apply { layoutParams = LinearLayout.LayoutParams(1, dp(6f)) })

            // Row 2 资金出入账户选择
            accountLabel = TextView(context).apply {
                text = config.labels.accountExpense
                textSize = 10f
                paint.isFakeBoldText = true
                setTextColor(colorFgSecondary)
                setPadding(0, 0, 0, dp(2f))
            }
            container.addView(accountLabel)

            accountContainer = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
            }

            val accountScroll = HorizontalScrollView(context).apply {
                isHorizontalScrollBarEnabled = false
                addView(accountContainer)
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }
            container.addView(accountScroll)
            container.addView(View(context).apply { layoutParams = LinearLayout.LayoutParams(1, dp(10f)) })

            // 底部操作栏
            val btnContainer = LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
                gravity = Gravity.CENTER
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }

            // 1) 打开应用按钮
            val openAppBtn = Button(context).apply {
                text = config.labels.openApp
                setTextColor(colorFgPrimary)
                background = GradientDrawable().apply {
                    shape = GradientDrawable.RECTANGLE
                    cornerRadius = dp(12f).toFloat()
                    setColor(colorInputBg)
                    setStroke(dp(1f), colorBorder)
                }
                textSize = 11f
                layoutParams = LinearLayout.LayoutParams(0, dp(40f), 1f).apply { rightMargin = dp(6f) }
                setOnClickListener {
                    val newAmount = amountInput.text.toString().trim()
                    val newPayee = merchantInput.text.toString().trim()
                    val newNarration = narrationInput.text.toString().trim()

                    sendOpenAppEvent(newAmount, newPayee, newNarration, selectedCategoryAccount, selectedSourceAccount)
                    dismiss()
                    SelectToSpeakService.instance?.bringAppToForeground()
                }
            }

            // 2) 忽略按钮
            val cancelBtn = Button(context).apply {
                text = config.labels.dismiss
                setTextColor(colorFgPrimary)
                background = GradientDrawable().apply {
                    shape = GradientDrawable.RECTANGLE
                    cornerRadius = dp(12f).toFloat()
                    setColor(colorInputBg)
                    setStroke(dp(1f), colorBorder)
                }
                textSize = 11f
                layoutParams = LinearLayout.LayoutParams(0, dp(40f), 1f).apply { rightMargin = dp(6f) }
                setOnClickListener {
                    sendCancelEvent()
                    dismiss()
                }
            }

            // 3) 确认入账按钮
            saveBtn = Button(context).apply {
                text = config.labels.confirm
                setTextColor(colorAccentFg)
                background = GradientDrawable().apply {
                    shape = GradientDrawable.RECTANGLE
                    cornerRadius = dp(12f).toFloat()
                    setColor(colorAccent)
                }
                textSize = 11f
                paint.isFakeBoldText = true
                layoutParams = LinearLayout.LayoutParams(0, dp(40f), 1.3f)
                setOnClickListener {
                    val newAmount = amountInput.text.toString().trim()
                    val newPayee = merchantInput.text.toString().trim()
                    val newNarration = narrationInput.text.toString().trim()

                    sendSaveEvent(newAmount, newPayee, newNarration, selectedCategoryAccount, selectedSourceAccount)
                    dismiss()
                }
            }

            btnContainer.addView(openAppBtn)
            btnContainer.addView(cancelBtn)
            btnContainer.addView(saveBtn)
            container.addView(btnContainer)

            // 金额安全校验（BigDecimal + 正则）
            val amountWatcher = object : android.text.TextWatcher {
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
                override fun afterTextChanged(s: android.text.Editable?) {
                    try {
                        val text = s?.toString()?.trim() ?: ""
                        val pattern = Regex("^\\d+(\\.\\d{1,2})?$")
                        val value = text.toBigDecimalOrNull()
                        val isValid = pattern.matches(text) && value != null && value > BigDecimal.ZERO
                        saveBtn?.isEnabled = isValid
                        saveBtn?.background = GradientDrawable().apply {
                            shape = GradientDrawable.RECTANGLE
                            cornerRadius = dp(12f).toFloat()
                            setColor(if (isValid) colorAccent else colorInputBg)
                        }
                        saveBtn?.setTextColor(if (isValid) colorAccentFg else colorFgSecondary)
                    } catch (e: Exception) {
                        Log.e(TAG, "金额校验异常", e)
                        saveBtn?.isEnabled = false
                    }
                }
            }
            amountInput.addTextChangedListener(amountWatcher)

            // 填充金额触发 Watcher 校验
            amountInput.setText(amount)

            // 动态初始构建两行胶囊
            rebuildChips()

            view = container
            windowManager.addView(view, windowParams)
            Log.i(TAG, "悬浮修改记账面板已显示: $currentCurrency $amount")

            // 用户一旦进行任何交互（触摸面板或获得输入焦点），立刻取消自动消失定时器
            val cancelTimerListener = View.OnFocusChangeListener { _, hasFocus ->
                if (hasFocus) {
                    handler.removeCallbacksAndMessages(null)
                    Log.d(TAG, "已获得输入焦点，取消自动消失定时器")
                }
            }
            amountInput.onFocusChangeListener = cancelTimerListener
            merchantInput.onFocusChangeListener = cancelTimerListener
            narrationInput.onFocusChangeListener = cancelTimerListener

            container.setOnTouchListener { _, _ ->
                handler.removeCallbacksAndMessages(null)
                Log.d(TAG, "已触摸卡片，取消自动消失定时器")
                false
            }

            // 30 秒无操作自动消失（如果用户没有交互的话）
            handler.postDelayed({
                sendCancelEvent()
                dismiss()
            }, 30000L)

        } catch (e: Exception) {
            Log.e(TAG, "悬浮账单面板显示失败: ${e.message}", e)
        }
    }

    /** 动态根据交易方向重绘第一行与第二行滑动的胶囊列表 */
    private fun rebuildChips() {
        categoryContainer?.removeAllViews()
        accountContainer?.removeAllViews()

        val categoryChips = mutableListOf<Pair<String, TextView>>()
        val accountChips = mutableListOf<Pair<String, TextView>>()

        // === 1. 绘制第一行 (分类 / 转入) ===
        if (currentDirection == "expense") {
            categoryLabel?.text = config.labels.categoryExpense
            val filteredCats = categories.filter { it["type"] == "expense" }
            for (cat in filteredCats) {
                val catAccount = cat["account"] ?: ""
                val catName = cat["name"] ?: ""
                val chip = createChipView(catName)

                fun updateStyle(selected: String) {
                    for (pair in categoryChips) {
                        val active = pair.first == selected
                        pair.second.background = GradientDrawable().apply {
                            cornerRadius = dp(14f).toFloat()
                            if (active) setColor(colorAccent)
                            else {
                                setColor(colorInputBg)
                                setStroke(dp(1f), colorBorder)
                            }
                        }
                        pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
                    }
                }

                chip.setOnClickListener {
                    selectedCategoryAccount = catAccount
                    updateStyle(catAccount)
                }
                categoryContainer?.addView(chip)
                categoryChips.add(catAccount to chip)
            }
            selectedCategoryAccount = filteredCats.firstOrNull()?.get("account") ?: ""
            categoryChips.forEach { pair ->
                val active = pair.first == selectedCategoryAccount
                pair.second.background = GradientDrawable().apply {
                    cornerRadius = dp(14f).toFloat()
                    if (active) setColor(colorAccent)
                    else {
                        setColor(colorInputBg)
                        setStroke(dp(1f), colorBorder)
                    }
                }
                pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
            }

        } else if (currentDirection == "income") {
            categoryLabel?.text = config.labels.categoryIncome
            val filteredCats = categories.filter { it["type"] == "income" }
            for (cat in filteredCats) {
                val catAccount = cat["account"] ?: ""
                val catName = cat["name"] ?: ""
                val chip = createChipView(catName)

                fun updateStyle(selected: String) {
                    for (pair in categoryChips) {
                        val active = pair.first == selected
                        pair.second.background = GradientDrawable().apply {
                            cornerRadius = dp(14f).toFloat()
                            if (active) setColor(colorAccent)
                            else {
                                setColor(colorInputBg)
                                setStroke(dp(1f), colorBorder)
                            }
                        }
                        pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
                    }
                }

                chip.setOnClickListener {
                    selectedCategoryAccount = catAccount
                    updateStyle(catAccount)
                }
                categoryContainer?.addView(chip)
                categoryChips.add(catAccount to chip)
            }
            selectedCategoryAccount = filteredCats.firstOrNull()?.get("account") ?: ""
            categoryChips.forEach { pair ->
                val active = pair.first == selectedCategoryAccount
                pair.second.background = GradientDrawable().apply {
                    cornerRadius = dp(14f).toFloat()
                    if (active) setColor(colorAccent)
                    else {
                        setColor(colorInputBg)
                        setStroke(dp(1f), colorBorder)
                    }
                }
                pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
            }

        } else {
            // transfer — 第一行 = 转入账户，选中色 = transfer
            categoryLabel?.text = config.labels.transferTarget
            for (acct in accounts) {
                val shortName = acct.split(":").lastOrNull() ?: acct
                val chip = createChipView(shortName)

                fun updateStyle(selected: String) {
                    for (pair in categoryChips) {
                        val active = pair.first == selected
                        pair.second.background = GradientDrawable().apply {
                            cornerRadius = dp(14f).toFloat()
                            if (active) setColor(colorTransfer)
                            else {
                                setColor(colorInputBg)
                                setStroke(dp(1f), colorBorder)
                            }
                        }
                        pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
                    }
                }

                chip.setOnClickListener {
                    selectedCategoryAccount = acct
                    updateStyle(acct)
                }
                categoryContainer?.addView(chip)
                categoryChips.add(acct to chip)
            }
            selectedCategoryAccount = if (accounts.size > 1 && accounts[0] == selectedSourceAccount) accounts[1] else (accounts.firstOrNull() ?: "")
            categoryChips.forEach { pair ->
                val active = pair.first == selectedCategoryAccount
                pair.second.background = GradientDrawable().apply {
                    cornerRadius = dp(14f).toFloat()
                    if (active) setColor(colorTransfer)
                    else {
                        setColor(colorInputBg)
                        setStroke(dp(1f), colorBorder)
                    }
                }
                pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
            }
        }

        // === 2. 绘制第二行 (资金账户) ===
        if (currentDirection == "expense") {
            accountLabel?.text = config.labels.accountExpense
        } else if (currentDirection == "income") {
            accountLabel?.text = config.labels.accountIncome
        } else {
            accountLabel?.text = config.labels.accountTransfer
        }

        // 账户行选中色按方向：expense→expense色，income→income色，transfer→expense色
        val accountSelectedColor = if (currentDirection == "income") colorIncome else colorExpense

        for (acct in accounts) {
            val shortName = acct.split(":").lastOrNull() ?: acct
            val chip = createChipView(shortName)

            fun updateStyle(selected: String) {
                for (pair in accountChips) {
                    val active = pair.first == selected
                    pair.second.background = GradientDrawable().apply {
                        cornerRadius = dp(14f).toFloat()
                        if (active) {
                            setColor(accountSelectedColor)
                        } else {
                            setColor(colorInputBg)
                            setStroke(dp(1f), colorBorder)
                        }
                    }
                    pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
                }
            }

            chip.setOnClickListener {
                selectedSourceAccount = acct
                updateStyle(acct)

                // 若是转账，且转入转出账户冲突，自动移开转入账户
                if (currentDirection == "transfer" && selectedCategoryAccount == selectedSourceAccount) {
                    val nextAvail = categoryChips.find { it.first != selectedSourceAccount }
                    if (nextAvail != null) {
                        selectedCategoryAccount = nextAvail.first
                        for (p in categoryChips) {
                            val act = p.first == selectedCategoryAccount
                            p.second.background = GradientDrawable().apply {
                                cornerRadius = dp(14f).toFloat()
                                if (act) setColor(colorTransfer)
                                else {
                                    setColor(colorInputBg)
                                    setStroke(dp(1f), colorBorder)
                                }
                            }
                            p.second.setTextColor(if (act) colorAccentFg else colorFgSecondary)
                        }
                    }
                }
            }
            accountContainer?.addView(chip)
            accountChips.add(acct to chip)
        }

        selectedSourceAccount = accounts.firstOrNull() ?: ""
        accountChips.forEach { pair ->
            val active = pair.first == selectedSourceAccount
            pair.second.background = GradientDrawable().apply {
                cornerRadius = dp(14f).toFloat()
                if (active) {
                    setColor(accountSelectedColor)
                } else {
                    setColor(colorInputBg)
                    setStroke(dp(1f), colorBorder)
                }
            }
            pair.second.setTextColor(if (active) colorAccentFg else colorFgSecondary)
        }
    }

    /** 推送保存事件到 JS 层。 */
    private fun sendSaveEvent(newAmount: String, newPayee: String, newNarration: String, categoryAccount: String, sourceAccount: String) {
        val reactContext = ReactContextHolder.context ?: return
        try {
            val map = WritableNativeMap().apply {
                putString("draftId", draftId)
                putString("amount", newAmount)
                putString("merchant", newPayee)
                putString("narration", newNarration)
                putString("category", categoryAccount)
                putString("account", sourceAccount)
                putString("time", time)
                putString("direction", currentDirection)
                putString("packageName", packageName)
                putString("currency", currentCurrency)
                putBoolean("confirmed", true)
                putBoolean("editRequested", false)
                putBoolean("isManualEdit", true)
            }
            reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit("billingConfirmed", map)
        } catch (e: Exception) {
            Log.e(TAG, "推送修改保存事件失败: ${e.message}")
        }
    }

    /** 推送打开应用事件到 JS 层，以便前台加载详细表单。 */
    private fun sendOpenAppEvent(newAmount: String, newPayee: String, newNarration: String, categoryAccount: String, sourceAccount: String) {
        val reactContext = ReactContextHolder.context ?: return
        try {
            val map = WritableNativeMap().apply {
                putString("draftId", draftId)
                putString("amount", newAmount)
                putString("merchant", newPayee)
                putString("narration", newNarration)
                putString("category", categoryAccount)
                putString("account", sourceAccount)
                putString("time", time)
                putString("direction", currentDirection)
                putString("packageName", packageName)
                putString("currency", currentCurrency)
            }
            reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit("billingOpenApp", map)
        } catch (e: Exception) {
            Log.e(TAG, "推送打开应用事件失败: ${e.message}")
        }
    }

    /** 推送取消/忽略事件到 JS 层。 */
    private fun sendCancelEvent() {
        val reactContext = ReactContextHolder.context ?: return
        try {
            val map = WritableNativeMap().apply {
                putString("draftId", draftId)
                putBoolean("confirmed", false)
            }
            reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit("billingConfirmed", map)
        } catch (e: Exception) {
            Log.e(TAG, "推送取消事件失败: ${e.message}")
        }
    }

    /** 关闭浮窗。 */
    fun dismiss() {
        handler.removeCallbacksAndMessages(null)
        try {
            view?.let { windowManager.removeView(it) }
        } catch (_: Exception) {}
        view = null
    }

    /** Kotlin 中缺失的 toBigDecimalOrNull 扩展。 */
    private fun String.toBigDecimalOrNull(): BigDecimal? {
        return try {
            BigDecimal(this)
        } catch (_: Exception) {
            null
        }
    }
}
