"""共享工具函数：符号表处理中使用的 AST 分析工具"""
from __future__ import annotations
import ast
from lib.includes import t

_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})


def IsTModule(module_id: str, symtable: object | None = None) -> bool:
    """检查模块标识符是否指向 t 类型模块（支持别名如 import t as tt）"""
    if module_id in _T_MODULE_NAMES:
        return True
    if symtable is not None and hasattr(symtable, 'import_aliases'):
        resolved: str = symtable.import_aliases.get(module_id, module_id)
        if resolved in _T_MODULE_NAMES:
            return True
    return False


def IsTModulePath(module_path: str) -> bool:
    """检查模块路径是否指向 t 类型模块"""
    if module_path in _T_MODULE_NAMES:
        return True
    if module_path:
        t_name: str
        for t_name in _T_MODULE_NAMES:
            if module_path == t_name or module_path.startswith(t_name + '.'):
                return True
    return False


def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool:
    """检测 AST 节点中是否包含指定名称的 t 模块类型"""
    if isinstance(node, ast.Attribute):
        if (hasattr(node.value, 'id') and IsTModule(node.value.id) and
            node.attr == TypeName):
            return True
    elif isinstance(node, ast.BinOp):
        return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName)
    elif isinstance(node, ast.Call):
        if AnnotationContainsTType(node.func, TypeName):
            return True
        for arg in node.args:
            if AnnotationContainsTType(arg, TypeName):
                return True
    elif isinstance(node, ast.Subscript):
        if AnnotationContainsTType(node.value, TypeName):
            return True
        if AnnotationContainsTType(node.slice, TypeName):
            return True
    return False


def IsListAnnotation(annotation: ast.expr) -> bool:
    """检查注解是否为栈上固定数组类型（t.CArray[...] 或 list[type, count]）"""
    if not isinstance(annotation, ast.Subscript):
        return False
    value = annotation.value
    # t.CArray[...]
    if (isinstance(value, ast.Attribute)
            and isinstance(value.value, ast.Name)
            and value.value.id == 't'
            and value.attr == 'CArray'):
        return True
    # list[type, count] — 仅匹配双参数 Tuple 切片（固定数组），
    # 单参数 list[type] 不匹配（走泛型类 list[T] 路径）
    if (isinstance(value, ast.Name)
            and value.id == 'list'
            and isinstance(annotation.slice, ast.Tuple)
            and len(annotation.slice.elts) == 2):
        return True
    return False


def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
    """从 BinOp(BitOr) 注解中提取 list[...] 部分，如 list[i32] | t.CPtr"""
    if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
        for side in (annotation.left, annotation.right):
            if IsListAnnotation(side):
                return side
    return None


class ListAnnotationParseResult:
    """list[...] 注解解析结果。

    is_pointer=True 表示单参数 list[type] → 指针模式；
    is_pointer=False 表示 Tuple(2) 模式 list[type, count]。
    """
    __slots__ = ('elem_type_node', 'count_node', 'is_pointer')

    def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None:
        self.elem_type_node: ast.expr = elem_type_node
        self.count_node: ast.expr | None = count_node
        self.is_pointer: bool = is_pointer


def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
    """解析 list[...] 注解，统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。

    自动处理 BinOp(BitOr) 包裹（如 list[i32, N] | t.CPtr）。
    返回 None 表示不是 list 注解。
    """
    list_node: ast.expr = annotation
    if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
        extracted: ast.Subscript | None = ExtractListFromBinOp(annotation)
        if extracted is None:
            return None
        list_node = extracted
    if not IsListAnnotation(list_node):
        return None
    slice_node: ast.AST = list_node.slice
    if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
        return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False)
    # 单参数 list[type] → 指针模式
    return ListAnnotationParseResult(slice_node, None, is_pointer=True)


def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
    """检测注解节点中是否包含 CInline"""
    if annotation_node is None:
        return False
    if isinstance(annotation_node, ast.Attribute):
        if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline':
            return True
    if isinstance(annotation_node, ast.Name):
        if annotation_node.id == 'CInline':
            return True
    if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
        return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
    return False


def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
    """从 BinOp(BitOr) 注解左侧提取类型名（如 TypeA | TypeB → TypeA）。

    返回 Name.id 或 Attribute.attr，非 BinOp 返回 None。
    """
    if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
        left: ast.expr = annotation.left
        if isinstance(left, ast.Name):
            return left.id
        if isinstance(left, ast.Attribute):
            return left.attr
    return None


def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
    """递归在注解中查找结构体名（支持 BinOp(BitOr) 递归）。

    检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
    支持泛型特化类型（如 GSList[Param]），构造特化名后检查是否在 struct_names 中。
    """
    if isinstance(node, ast.Name) and node.id in struct_names:
        return node.id
    if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names:
        return node.value
    if isinstance(node, ast.Attribute) and node.attr in struct_names:
        return node.attr
    if isinstance(node, ast.Subscript):
        base_name: str | None = None
        if isinstance(node.value, ast.Name):
            base_name = node.value.id
        elif isinstance(node.value, ast.Attribute):
            base_name = node.value.attr
        if base_name:
            slice_node: ast.AST = node.slice
            if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
                slice_node = slice_node.value
            type_args: list[str] = []
            if isinstance(slice_node, ast.Name):
                type_args.append(slice_node.id)
            elif isinstance(slice_node, ast.Attribute):
                type_args.append(slice_node.attr)
            elif isinstance(slice_node, ast.Tuple):
                for elt in slice_node.elts:
                    if isinstance(elt, ast.Name):
                        type_args.append(elt.id)
                    elif isinstance(elt, ast.Attribute):
                        type_args.append(elt.attr)
            if type_args:
                spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
                if spec_name in struct_names:
                    return spec_name
            if base_name in struct_names:
                return base_name
    if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
        result: str | None = FindStructNameInAnnotation(node.left, struct_names)
        if result:
            return result
        return FindStructNameInAnnotation(node.right, struct_names)
    return None


def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
    """检查注解中是否包含指定名称（支持 BinOp(BitOr) 递归）。

    同时检查 Attribute.attr 和 Name.id，比 ast.dump 字符串匹配更精确。
    """
    if isinstance(annotation, ast.Attribute):
        return annotation.attr == name
    if isinstance(annotation, ast.Name):
        return annotation.id == name
    if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
        return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
    return False
