import t, c
from stdint import *
import ast
import memhub
import string
import viperlib
import stdio
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesStruct as HandlesStruct


# ============================================================
# HandlesImports - 导入语句处理（Mixin 继承模式）
#
# 管理 _imported_modules 和 _from_imports 字符串
# 注意：str = bytes = t.CChar | t.CPtr = i8*
# ============================================================


# ============================================================
# 模块级工具函数（保留供外部调用）
# ============================================================

# ============================================================
# 添加已导入模块名
# ============================================================
def add_imported_module(pool: memhub.MemBuddy | t.CPtr,
                        imported_modules: str,
                        name: str) -> str:
    """记录已导入的模块名，返回新的 imported_modules 字符串指针"""
    if name is None:
        return imported_modules
    if imported_modules is None:
        nlen: t.CSizeT = string.strlen(name)
        buf: t.CChar | t.CPtr = pool.alloc(nlen + 1)
        if buf is not None:
            string.strcpy(buf, name)
            return buf
        return None
    else:
        old_len: t.CSizeT = string.strlen(imported_modules)
        name_len: t.CSizeT = string.strlen(name)
        new_len: t.CSizeT = old_len + 1 + name_len
        buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1)
        if buf2 is not None:
            string.strcpy(buf2, imported_modules)
            buf2[old_len] = ' '
            string.strcpy(buf2 + old_len + 1, name)
            return buf2
        return imported_modules


# ============================================================
# 检查模块是否已导入
# ============================================================
def is_module_imported(imported_modules: str, name: str) -> int:
    """检查模块是否已导入（词边界精确匹配，避免子串误匹配）"""
    if name is None or imported_modules is None:
        return 0
    name_len: t.CSizeT = string.strlen(name)
    cur: t.CChar | t.CPtr = imported_modules
    total_len: t.CSizeT = string.strlen(imported_modules)
    ci: t.CSizeT = 0
    while ci < total_len:
        while ci < total_len and cur[ci] == ' ':
            ci += 1
        if ci >= total_len:
            break
        word_start: t.CSizeT = ci
        while ci < total_len and cur[ci] != ' ':
            ci += 1
        word_len: t.CSizeT = ci - word_start
        if word_len == name_len:
            match: int = 1
            for ei in range(name_len):
                if cur[word_start + ei] != name[ei]:
                    match = 0
                    break
            if match == 1:
                return 1
    return 0


# ============================================================
# 添加 from-import 名称映射
# ============================================================
def add_from_import(pool: memhub.MemBuddy | t.CPtr,
                    from_imports: str,
                    local_name: str,
                    module_name: str) -> str:
    """添加 from-import 映射 "name:module"，返回新的 from_imports 字符串"""
    if local_name is None or module_name is None:
        return from_imports
    entry: t.CChar | t.CPtr = pool.alloc(128)
    if entry is None:
        return from_imports
    viperlib.snprintf(entry, 128, "%s:%s", local_name, module_name)
    if from_imports is None:
        return entry
    else:
        old_len: t.CSizeT = string.strlen(from_imports)
        entry_len: t.CSizeT = string.strlen(entry)
        new_len: t.CSizeT = old_len + 1 + entry_len
        buf: t.CChar | t.CPtr = pool.alloc(new_len + 1)
        if buf is not None:
            string.strcpy(buf, from_imports)
            buf[old_len] = ' '
            string.strcpy(buf + old_len + 1, entry)
            return buf
        return from_imports


# ============================================================
# 查找 from-import 名称 → 返回模块名或 None
#
# allow_star_fallback: 是否允许 star import 回退（默认 1=允许）。
#   当查询明确模块名（如 "BuildPipeline"）时，应传 0 禁用回退，
#   避免被 star import 模块名误导（如 from stdint import * 后
#   查询 "BuildPipeline" 错误回退到 "stdint"）。
# ============================================================
def lookup_from_import(from_imports: str, name: str,
                       allow_star_fallback: int = 1) -> str:
    """查找 from-import 名称，返回模块名或 None

    支持 star import: 如果 from_imports 中有 "*:module" 条目，
    且未找到精确名称匹配，且 allow_star_fallback != 0，则返回 star import 的模块名。
    """
    if name is None or from_imports is None:
        return None
    name_len: t.CSizeT = string.strlen(name)
    cur: t.CChar | t.CPtr = from_imports
    ci: t.CSizeT = 0
    total_len: t.CSizeT = string.strlen(from_imports)
    star_mod: str = None
    while ci < total_len:
        # 跳过前导空格
        while ci < total_len and cur[ci] == ' ':
            ci += 1
        if ci >= total_len:
            break
        # 找到 ':' 的位置
        colon_pos: t.CSizeT = ci
        while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ':
            colon_pos += 1
        if colon_pos >= total_len or cur[colon_pos] != ':':
            break
        entry_name_len: t.CSizeT = colon_pos - ci
        # 检测 star import ("*:module")
        if entry_name_len == 1 and cur[ci] == '*':
            mod_start: t.CSizeT = colon_pos + 1
            mod_end: t.CSizeT = mod_start
            while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0':
                mod_end += 1
            star_mod = cur + mod_start
        # 比较名称
        elif entry_name_len == name_len:
            match: int = 1
            ei: t.CSizeT = 0
            while ei < name_len:
                if cur[ci + ei] != name[ei]:
                    match = 0
                    break
                ei += 1
            if match == 1:
                mod_start2: t.CSizeT = colon_pos + 1
                mod_end2: t.CSizeT = mod_start2
                while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0':
                    mod_end2 += 1
                return cur + mod_start2
        # 跳到下一个条目
        ci = colon_pos
        while ci < total_len and cur[ci] != ' ':
            ci += 1
    # 未找到精确匹配，仅在允许时回退到 star import
    if allow_star_fallback == 0:
        return None
    return star_mod


# ============================================================
# _resolve_relative_module - 解析相对导入为完整模块名
#
# 对于 from .X import Y（level=1, module="X"）在包 pkg 中：
#   解析为 "pkg.X"
# 对于 from . import Y（level=1, module=None）在包 pkg 中：
#   解析为 "pkg"
# 对于 from ..X import Y（level=2, module="X"）在包 pkg.sub 中：
#   解析为 "pkg.X"（先从 pkg.sub 上溯一级到 pkg，再追加 .X）
#
# Args:
#   pool: 内存池
#   current_package: 当前文件所属包名（如 "llvmlite"），None 表示无包
#   level: 相对导入级别（0=绝对，1=., 2=..）
#   module: ImportFrom 的 module 字段（可能为 None）
#
# Returns:
#   解析后的完整模块名；绝对导入（level<=0）直接返回 module；
#   无法解析时返回 module（回退到原始值）
# ============================================================
def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
                            current_package: str,
                            level: t.CInt,
                            module: str) -> str:
    """解析相对导入为完整模块名"""
    if level <= 0:
        return module
    if current_package is None:
        return module

    # 从 current_package 开始，上溯 (level-1) 级
    pkg: str = current_package
    up: t.CInt = level - 1
    while up > 0:
        pkg_len: t.CSizeT = string.strlen(pkg)
        last_dot: t.CSizeT = 0
        found: int = 0
        i: t.CSizeT = 0
        while i < pkg_len:
            if pkg[i] == '.':
                last_dot = i
                found = 1
            i += 1
        if found == 0:
            # 无更多父级，包变为空
            pkg = None
            break
        # 截断到最后一个 '.' 处
        new_pkg: str = pool.alloc(last_dot + 1)
        if new_pkg is None:
            return module
        string.strncpy(new_pkg, pkg, last_dot)
        new_pkg[last_dot] = '\0'
        pkg = new_pkg
        up -= 1

    if module is None:
        # from . import Y → 模块就是包本身
        return pkg
    if pkg is None:
        # 包已上溯到空，直接用 module
        return module
    # 拼接 pkg + "." + module
    pkg_len2: t.CSizeT = string.strlen(pkg)
    mod_len: t.CSizeT = string.strlen(module)
    buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
    if buf is None:
        return module
    string.strcpy(buf, pkg)
    buf[pkg_len2] = '.'
    string.strcpy(buf + pkg_len2 + 1, module)
    return buf


# ============================================================
# compute_package_from_relpath - 从相对路径计算包名
#
# 包名 = 文件所在目录路径，将 / 和 \ 替换为 .
# 对于顶级文件（无目录分隔符），返回 None
#
# 示例：
#   "llvmlite/__init__.py" → "llvmlite"
#   "llvmlite/__types.py"  → "llvmlite"
#   "ast/parser.py"        → "ast"
#   "ast.py"               → None（顶级文件）
# ============================================================
def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr,
                                rel_path: str) -> str:
    """从相对路径计算包名（目录部分，分隔符替换为 .）"""
    if rel_path is None:
        return None
    rlen: t.CSizeT = string.strlen(rel_path)
    # 找最后一个 / 或 \
    last_sep: t.CSizeT = 0
    found: int = 0
    i: t.CSizeT = 0
    while i < rlen:
        ch: t.CChar = rel_path[i]
        if ch == '/' or ch == '\\':
            last_sep = i
            found = 1
        i += 1
    if found == 0:
        # 无目录分隔符 → 顶级文件，无包
        return None
    # 复制目录部分，将 / 和 \ 替换为 .
    dir_len: t.CSizeT = last_sep
    buf: str = pool.alloc(dir_len + 1)
    if buf is None:
        return None
    j: t.CSizeT = 0
    while j < dir_len:
        ch2: t.CChar = rel_path[j]
        if ch2 == '/' or ch2 == '\\':
            buf[j] = '.'
        else:
            buf[j] = ch2
        j += 1
    buf[dir_len] = '\0'
    return buf


# ============================================================
# ImportsHandle - 导入语句处理器（Mixin 继承模式）
#
# 方法版本：直接更新 trans._imported_modules / trans._from_imports
# ============================================================
@t.NoVTable
class ImportsHandle(HandlesBase.Mixin):
    """导入语句处理器：继承 Mixin 获得 Trans 回指针"""

    def __init__(self, trans: HT.Translator | t.CPtr):
        self.Trans = trans

    # ============================================================
    # HandleImport - 处理 import 语句，更新 trans._imported_modules
    # ============================================================
    def HandleImport(self, node: ast.AST | t.CPtr) -> int:
        """处理 import 语句，返回 0"""
        imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
        if imp is None:
            return 0
        names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
        if names is None:
            return 0
        nn: t.CSizeT = names.__len__()
        for ni in range(nn):
            alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
            if alias is not None and alias.name is not None:
                pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool
                im_val: str = self.Trans._imported_modules
                self.Trans._imported_modules = add_imported_module(
                    pool_val, im_val, alias.name)
                # 别名也加入导入模块列表（用于模块限定构造器检查 Module.Class()）
                if alias.asname is not None:
                    self.Trans._imported_modules = add_imported_module(
                        pool_val, self.Trans._imported_modules, alias.asname)
        return 0

    # ============================================================
    # HandleImportFromModule - 处理 from X import Y 的模块部分
    #
    # 对相对导入（level > 0），使用 trans.CurrentPackage 解析为
    # 完整模块名（如 __types → llvmlite.__types），确保 .deps.txt
    # 记录的模块名与 SHA1 映射表一致。
    # ============================================================
    def HandleImportFromModule(self, node: ast.AST | t.CPtr) -> int:
        """处理 from X import Y 的模块部分，更新 trans._imported_modules"""
        impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
        if impf is None:
            return 0
        # 解析模块名：相对导入需补充包前缀
        resolved: str = _resolve_relative_module(
            self.Trans.Pool, self.Trans.CurrentPackage,
            impf.level, impf.module)
        if resolved is not None:
            self.Trans._imported_modules = add_imported_module(
                self.Trans.Pool, self.Trans._imported_modules, resolved)
        return 0

    # ============================================================
    # HandleImportFromNames - 处理 from X import Y 的名称部分
    #
    # 同样使用解析后的完整模块名，确保 from-import 映射
    # （如 LLVMType:llvmlite.__types）能正确查到 SHA1。
    # ============================================================
    def HandleImportFromNames(self, node: ast.AST | t.CPtr) -> int:
        """处理 from X import Y 的名称部分，更新 trans._from_imports"""
        impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
        if impf is None:
            return 0
        # 解析模块名：相对导入需补充包前缀
        resolved: str = _resolve_relative_module(
            self.Trans.Pool, self.Trans.CurrentPackage,
            impf.level, impf.module)
        if resolved is not None:
            names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
            if names is not None:
                nn: t.CSizeT = names.__len__()
                for ni in range(nn):
                    alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
                    if alias is not None and alias.name is not None:
                        local_name: str = alias.name
                        if alias.asname is not None:
                            local_name = alias.asname
                        self.Trans._from_imports = add_from_import(
                            self.Trans.Pool, self.Trans._from_imports,
                            local_name, resolved)
                        # 命名空间隔离：from-import 的名称标记为可见结构体
                        HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
        return 0


# ============================================================
# NewImportsHandle - 工厂函数
# ============================================================
def NewImportsHandle(pool: memhub.MemBuddy | t.CPtr,
                     trans: HT.Translator | t.CPtr) -> ImportsHandle | t.CPtr:
    h: ImportsHandle | t.CPtr = pool.alloc(ImportsHandle.__sizeof__())
    if h is None:
        return None
    string.memset(h, 0, ImportsHandle.__sizeof__())
    h.Trans = trans
    return h
