from __future__ import annotations

import json
from typing import Any, Dict, List, Union, Tuple


def 遍历_键_取层级和值(
    数据对象: Union[Dict[str, Any], List[Any], str, bytes, bytearray],
    目标键: str,
    *,
    去重值: bool = False,
    排序层级: bool = True,
    包含路径: bool = False,
) -> Union[Dict[int, List[Any]], Dict[int, List[Tuple[str, Any]]]]:
    """
    遍历嵌套数据结构，按层级聚合收集目标键的所有值。

    本函数对嵌套的 dict / list 数据进行深度优先遍历（DFS），
    当遍历到 dict 节点且包含目标键时，记录该键对应的值，
    并按该 dict 节点所在层级（depth）进行聚合。

    层级定义：
        - 根节点为第 0 层。
        - 进入 dict 的 value，层级 +1。
        - 进入 list 的 element，层级 +1。
        - 仅 dict 节点具备键；list 仅作为结构容器参与层级计算。

    Args:
        数据对象:
            待遍历的数据结构，支持 dict、list，
            以及可被解析为 JSON 的 str、bytes、bytearray。
        目标键:
            需要检索的键名，仅对 dict 节点生效。
        去重值:
            是否在“同一层级”内对收集到的值去重（保持原顺序）。
            默认 False。
        排序层级:
            是否对返回结果按层级升序排列（通过重新构造 dict 实现）。
            默认 True。
        包含路径:
            是否同时返回值的来源路径。
            - False：返回 {层级: [值...]}
            - True：返回 {层级: [(路径, 值)...]}
            默认 False。

    Returns:
        dict:
            - 包含路径=False：返回 Dict[int, List[Any]]，按层级聚合的值列表。
            - 包含路径=True：返回 Dict[int, List[Tuple[str, Any]]]，包含路径与值。
            - 未命中或发生异常时返回空字典 {}。
    """
    try:
        if isinstance(数据对象, (str, bytes, bytearray)):
            数据对象 = json.loads(数据对象)

        if 包含路径:
            结果2: Dict[int, List[Tuple[str, Any]]] = {}
            _递归收集_键层级和值_含路径(数据对象, 目标键, 0, "$", 结果2)
            if 去重值:
                _同层去重_含路径(结果2)
            if 排序层级:
                return {k: 结果2[k] for k in sorted(结果2)}
            return 结果2

        结果: Dict[int, List[Any]] = {}
        _递归收集_键层级和值(数据对象, 目标键, 0, 结果)
        if 去重值:
            _同层去重(结果)
        if 排序层级:
            return {k: 结果[k] for k in sorted(结果)}
        return 结果
    except Exception:
        return {}


def _递归收集_键层级和值(
    节点: Any,
    目标键: str,
    当前层级: int,
    结果: Dict[int, List[Any]],
) -> None:
    """DFS：遇到包含目标键的 dict，记录其所在层级的值。"""
    if isinstance(节点, dict):
        if 目标键 in 节点:
            结果.setdefault(当前层级, []).append(节点[目标键])
        for v in 节点.values():
            _递归收集_键层级和值(v, 目标键, 当前层级 + 1, 结果)
    elif isinstance(节点, list):
        for el in 节点:
            _递归收集_键层级和值(el, 目标键, 当前层级 + 1, 结果)


def _递归收集_键层级和值_含路径(
    节点: Any,
    目标键: str,
    当前层级: int,
    当前路径: str,
    结果: Dict[int, List[Tuple[str, Any]]],
) -> None:
    """DFS：遇到包含目标键的 dict，记录 (路径, 值)。"""
    if isinstance(节点, dict):
        if 目标键 in 节点:
            结果.setdefault(当前层级, []).append((f"{当前路径}.{目标键}", 节点[目标键]))
        for k, v in 节点.items():
            # dict 的 value 进入下一层
            _递归收集_键层级和值_含路径(v, 目标键, 当前层级 + 1, f"{当前路径}.{k}", 结果)
    elif isinstance(节点, list):
        for i, el in enumerate(节点):
            # list 的 element 进入下一层
            _递归收集_键层级和值_含路径(el, 目标键, 当前层级 + 1, f"{当前路径}[{i}]", 结果)


def _同层去重(结果: Dict[int, List[Any]]) -> None:
    """同层去重（保持原顺序），用于值不可哈希时也能工作。"""
    for lv, vals in list(结果.items()):
        新列表: List[Any] = []
        for v in vals:
            if not any(_深比较_相等(v, x) for x in 新列表):
                新列表.append(v)
        结果[lv] = 新列表


def _同层去重_含路径(结果: Dict[int, List[Tuple[str, Any]]]) -> None:
    """同层去重（保持原顺序），按“值”去重，路径保留第一个出现的。"""
    for lv, items in list(结果.items()):
        新列表: List[Tuple[str, Any]] = []
        for p, v in items:
            if not any(_深比较_相等(v, exist_v) for _, exist_v in 新列表):
                新列表.append((p, v))
        结果[lv] = 新列表


def _深比较_相等(a: Any, b: Any) -> bool:
    """尽量稳定的相等判断：优先 ==，失败则退回到类型+repr。"""
    try:
        return a == b
    except Exception:
        return type(a) is type(b) and repr(a) == repr(b)