package com.jishisongfu.duobibi.floating

import android.view.accessibility.AccessibilityNodeInfo

object TreeSerializer {

    private const val MAX_NODES = 1500
    private const val MAX_DEPTH = 25
    private const val MAX_STR = 200

    fun serialize(root: AccessibilityNodeInfo): NodeDto {
        var budget = MAX_NODES
        return convert(root, depth = 0) { budget-- > 0 }
    }

    private fun convert(
        node: AccessibilityNodeInfo,
        depth: Int,
        consumeBudget: () -> Boolean,
    ): NodeDto {
        if (!consumeBudget()) return NodeDto()
        val viewId = node.viewIdResourceName?.substringAfter(":id/", missingDelimiterValue = "")
            ?.takeIf { it.isNotBlank() }
        val text = node.text?.toString()?.take(MAX_STR)?.takeIf { it.isNotBlank() }
        val desc = node.contentDescription?.toString()?.take(MAX_STR)?.takeIf { it.isNotBlank() }

        val children = mutableListOf<NodeDto>()
        if (depth < MAX_DEPTH) {
            for (i in 0 until node.childCount) {
                val child = node.getChild(i) ?: continue
                if (!child.isVisibleToUser) {
                    child.recycleSafely()
                    continue
                }
                val converted = convert(child, depth + 1, consumeBudget)
                if (converted.viewId != null || converted.text != null ||
                    converted.desc != null || converted.children.isNotEmpty()
                ) {
                    children.add(converted)
                }
                child.recycleSafely()
            }
        }

        return NodeDto(viewId = viewId, text = text, desc = desc, children = children)
    }

    @Suppress("DEPRECATION")
    private fun AccessibilityNodeInfo.recycleSafely() {
        // Android API 33 起,recycle() 已被标记为 no-op。这里包一层避免反复改写。
        try { recycle() } catch (_: Throwable) {}
    }
}
