import t, c
from stdint import *
import string
import memhub
import platmacro


# 模块级全局 MBuddy 指针（由用户在 main 中赋值初始化）
_mbuddy: memhub.MemBuddy | t.CPtr


# =============================================================================
# 路径分隔符
# =============================================================================

def sep() -> t.CChar:
    """返回当前平台的路径分隔符（Windows: \\，POSIX: /）"""
    if platmacro.IS_WINDOWS:
        return '\\'
    return '/'


def _is_sep(ch: t.CChar) -> bool:
    """判断字符是否为路径分隔符（/ 或 \\，跨平台识别）"""
    return ch == '/' or ch == '\\'


# =============================================================================
# 内部辅助函数
# =============================================================================

def _dup_str(s: str) -> str:
    """复制字符串（通过全局 MBuddy 分配内存）"""
    if s == None: return None
    length: t.CSizeT = len(s)
    buf: bytes = _mbuddy.alloc(length + 1)
    if buf == None: return None
    i: t.CSizeT = 0
    for ch in s:
        buf[i] = ch
        i += 1
    buf[length] = 0
    return str(buf)


def _substr(s: str, start: t.CSizeT, end: t.CSizeT) -> str:
    """提取子串 s[start:end]（通过全局 MBuddy 分配内存）"""
    if s == None: return None
    if start >= end: return _dup_str("")
    result_len: t.CSizeT = end - start
    buf: bytes = _mbuddy.alloc(result_len + 1)
    if buf == None: return None
    i: t.CSizeT = 0
    k: t.CSizeT = start
    while k < end:
        buf[i] = s[k]
        i += 1
        k += 1
    buf[i] = 0
    return str(buf)


# =============================================================================
# 路径判断
# =============================================================================

def isabs(path: str) -> bool:
    """判断路径是否为绝对路径。
    POSIX: 以 / 开头。
    Windows: 以 \\ 开头（UNC）或 X:\\ / X:/ 开头（盘符）。"""
    if path == None: return False
    if path[0] == 0: return False
    if path[0] == '/' or path[0] == '\\': return True
    if platmacro.IS_WINDOWS:
        # 检查 X:\ 或 X:/ 模式
        c0: t.CChar = path[0]
        if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'):
            if path[1] == ':':
                if path[2] == '\\' or path[2] == '/':
                    return True
    return False


# =============================================================================
# 路径拼接与分割
# =============================================================================

def join(path1: str, path2: str) -> str:
    """拼接两个路径。如果 path2 是绝对路径，返回 path2 的副本。"""
    if path1 == None or path1[0] == 0:
        return _dup_str(path2)
    if path2 == None or path2[0] == 0:
        return _dup_str(path1)
    if isabs(path2):
        return _dup_str(path2)

    len1: t.CSizeT = len(path1)
    len2: t.CSizeT = len(path2)

    # 检查 path1 是否以分隔符结尾
    need_sep: bool = True
    if _is_sep(path1[len1 - 1]):
        need_sep = False

    total: t.CSizeT = len1 + len2 + 1
    if need_sep:
        total += 1

    buf: bytes = _mbuddy.alloc(total)
    if buf == None: return None

    # 复制 path1
    i: t.CSizeT = 0
    for ch in path1:
        buf[i] = ch
        i += 1

    # 添加分隔符
    if need_sep:
        buf[i] = sep()
        i += 1

    # 复制 path2
    for ch in path2:
        buf[i] = ch
        i += 1

    buf[i] = 0
    return str(buf)


def basename(path: str) -> str:
    """返回路径的文件名部分（最后一个分隔符之后的内容）"""
    if path == None: return None
    length: t.CSizeT = len(path)
    if length == 0: return _dup_str("")

    # 从后向前找分隔符
    i: t.CSizeT = length
    while i > 0:
        i -= 1
        if _is_sep(path[i]):
            return _substr(path, i + 1, length)

    # 没有分隔符，返回整个路径的副本
    return _dup_str(path)


def dirname(path: str) -> str:
    """返回路径的目录部分（最后一个分隔符之前的内容）"""
    if path == None: return None
    length: t.CSizeT = len(path)
    if length == 0: return _dup_str("")

    # 从后向前找分隔符
    i: t.CSizeT = length
    while i > 0:
        i -= 1
        if _is_sep(path[i]):
            if i == 0:
                # 路径以分隔符开头，返回根目录
                return _dup_str("/")
            return _substr(path, 0, i)

    # 没有分隔符，返回空字符串
    return _dup_str("")


# =============================================================================
# 扩展名处理
# =============================================================================

def splitext_name(path: str) -> str:
    """返回路径去除扩展名后的主名部分。
    扩展名从最后一个 '.' 开始（该 '.' 不能是路径最后一个组件的第一个字符）。"""
    if path == None: return None
    length: t.CSizeT = len(path)
    if length == 0: return _dup_str("")

    # 从后向前找 '.'，遇到分隔符停止
    i: t.CSizeT = length
    while i > 0:
        i -= 1
        if path[i] == '.':
            return _substr(path, 0, i)
        if _is_sep(path[i]):
            break

    # 没有扩展名，返回整个路径的副本
    return _dup_str(path)


def splitext_ext(path: str) -> str:
    """返回路径的扩展名部分（包含 '.'）。无扩展名时返回空字符串。"""
    if path == None: return None
    length: t.CSizeT = len(path)
    if length == 0: return _dup_str("")

    # 从后向前找 '.'，遇到分隔符停止
    i: t.CSizeT = length
    while i > 0:
        i -= 1
        if path[i] == '.':
            return _substr(path, i, length)
        if _is_sep(path[i]):
            break

    # 没有扩展名，返回空字符串
    return _dup_str("")


# =============================================================================
# 路径规范化
# =============================================================================

def normpath(path: str) -> str:
    """规范化路径：统一分隔符、消除多余的 . 和 .. 组件、合并连续分隔符。
    注意：不解析符号链接，不调用系统 API。"""
    if path == None: return None
    length: t.CSizeT = len(path)
    if length == 0: return _dup_str(".")

    # 分配输出缓冲区（最坏情况：长度不变 + 前缀 /）
    buf: bytes = _mbuddy.alloc(length + 2)
    if buf == None: return None

    out_pos: t.CSizeT = 0
    i: t.CSizeT = 0
    s: str = sep()

    # 处理绝对路径前缀
    is_absolute: bool = False
    if _is_sep(path[0]):
        is_absolute = True
        buf[out_pos] = s
        out_pos += 1
        i = 1

    # Windows 盘符前缀（X:\ 或 X:/）
    drive_prefix_len: t.CSizeT = 0
    if platmacro.IS_WINDOWS:
        if length >= 3:
            c0: t.CChar = path[0]
            if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'):
                if path[1] == ':':
                    if _is_sep(path[2]):
                        buf[out_pos] = path[0]
                        out_pos += 1
                        buf[out_pos] = ':'
                        out_pos += 1
                        buf[out_pos] = s
                        out_pos += 1
                        drive_prefix_len = 3
                        i = 3
                        is_absolute = True

    # 逐组件处理
    while i < length:
        # 跳过连续分隔符
        while i < length and _is_sep(path[i]):
            i += 1
        if i >= length:
            break

        # 提取组件
        comp_start: t.CSizeT = i
        while i < length and not _is_sep(path[i]):
            i += 1
        comp_len: t.CSizeT = i - comp_start

        # 处理 "." 组件：跳过
        if comp_len == 1 and path[comp_start] == '.':
            continue

        # 处理 ".." 组件：回退一级
        if comp_len == 2 and path[comp_start] == '.' and path[comp_start + 1] == '.':
            if out_pos > drive_prefix_len:
                # 回退到上一个分隔符前
                out_pos -= 1
                while out_pos > drive_prefix_len and not _is_sep(buf[out_pos - 1]):
                    out_pos -= 1
                # 如果回退到了根目录前缀，不删除前缀
                if out_pos == drive_prefix_len and is_absolute:
                    out_pos = drive_prefix_len
                    if drive_prefix_len == 0:
                        # POSIX 根：保留 /
                        buf[out_pos] = s
                        out_pos += 1
            continue

        # 普通组件：复制到输出
        if out_pos > drive_prefix_len and not (drive_prefix_len == 0 and out_pos == 1 and is_absolute):
            buf[out_pos] = s
            out_pos += 1
        elif out_pos == 0 and not is_absolute:
            pass  # 第一个组件，不需要前导分隔符
        elif is_absolute and out_pos == drive_prefix_len:
            # 已经有前导分隔符，不重复添加
            pass
        else:
            buf[out_pos] = s
            out_pos += 1

        j: t.CSizeT = comp_start
        while j < comp_start + comp_len:
            buf[out_pos] = path[j]
            out_pos += 1
            j += 1

    # 处理空结果
    if out_pos == 0:
        buf[out_pos] = '.'
        out_pos += 1

    buf[out_pos] = 0
    return str(buf)
