from __future__ import annotations

from typing import Any, List, Sequence, Union


_路径类型 = Union[str, Sequence[Any]]


def _归一化路径(键路径: _路径类型, 分隔符: str) -> List[Any] | None:
    try:
        if isinstance(键路径, str):
            if 键路径 == "":
                return None
            return 键路径.split(分隔符)

        if isinstance(键路径, (list, tuple)):
            if len(键路径) == 0:
                return None
            return list(键路径)

        return None
    except Exception:
        return None


def 删除键_路径(
    数据: Any,
    键路径: _路径类型,
    分隔符: str = ".",
    键转字符串: bool = True,
) -> bool:
    """
    根据“键路径”从嵌套结构中安全删除目标项，支持 dict/list 混合结构。

    本函数用于删除深层路径上的键或索引项：
        - 父级为 dict 时，删除指定键；
        - 父级为 list 时，删除指定索引位置的元素。

    设计特性：
        - 支持字符串路径与路径序列；
        - 删除前会先逐层校验路径是否真实存在；
        - 不自动补结构，不做隐式修复；
        - 删除 list 元素时使用原地删除，后续索引会前移；
        - 不抛出任何异常，适合作为底层基础工具函数使用。

    行为说明：
        - 目标存在且删除成功        → 返回 True；
        - 路径不存在或类型不匹配    → 返回 False；
        - 数据不是可删除结构        → 返回 False。

    Args:
        数据 (Any): 通常为 dict 或 list 的嵌套结构。
        键路径 (str | Sequence[Any]): 路径字符串或路径序列。
            - 字符串示例： "a.b.0.c"
            - 列表示例： ["a", "b", 0, "c"]
        分隔符 (str): 字符串路径的分隔符，默认 "."。
        键转字符串 (bool): 当走 dict 路径时，是否将键统一转为 str。默认 True。

    Returns:
        bool:
            True  - 删除成功；
            False - 删除失败。
    """
    try:
        路径列表 = _归一化路径(键路径, 分隔符)
        if not 路径列表:
            return False

        if not isinstance(数据, (dict, list)):
            return False

        if len(路径列表) == 1:
            父级 = 数据
            末段 = 路径列表[0]
        else:
            父级 = 数据
            for 段 in 路径列表[:-1]:
                if isinstance(父级, dict):
                    键名 = str(段) if 键转字符串 else 段
                    if 键名 not in 父级:
                        return False
                    父级 = 父级[键名]
                    continue

                if isinstance(父级, (list, tuple)):
                    try:
                        目标索引 = 段 if isinstance(段, int) else int(str(段))
                    except Exception:
                        return False

                    if 目标索引 < 0 or 目标索引 >= len(父级):
                        return False

                    父级 = 父级[目标索引]
                    continue

                return False

            末段 = 路径列表[-1]

        if isinstance(父级, dict):
            键名 = str(末段) if 键转字符串 else 末段
            if 键名 not in 父级:
                return False
            del 父级[键名]
            return True

        if isinstance(父级, list):
            try:
                目标索引 = 末段 if isinstance(末段, int) else int(str(末段))
            except Exception:
                return False

            if 目标索引 < 0 or 目标索引 >= len(父级):
                return False

            del 父级[目标索引]
            return True

        return False
    except Exception:
        return False
