import t, c
from stdint import *
import w32.win32base
import w32.win32file
import memhub
import stdlib


# Windows 路径最大长度
MAX_PATH_LEN: t.CDefine = 260

# INVALID_FILE_ATTRIBUTES
INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF

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


# =============================================================================
# 文件/目录属性查询
# =============================================================================

def _get_attrs(path: str) -> ULONG:
    """获取文件属性。失败返回 INVALID_FILE_ATTRIBUTES。"""
    return w32.win32file.GetFileAttributesA(path)


def exists(path: str) -> bool:
    """检查文件/目录是否存在"""
    attrs: ULONG = _get_attrs(path)
    if attrs == INVALID_FILE_ATTRIBUTES:
        return False
    return True


def isdir(path: str) -> bool:
    """检查路径是否为目录"""
    attrs: ULONG = _get_attrs(path)
    if attrs == INVALID_FILE_ATTRIBUTES:
        return False
    if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
        return True
    return False


def isfile(path: str) -> bool:
    """检查路径是否为普通文件"""
    attrs: ULONG = _get_attrs(path)
    if attrs == INVALID_FILE_ATTRIBUTES:
        return False
    if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
        return False
    return True


def getsize(path: str) -> t.CInt64T:
    """返回文件大小（字节）。失败返回 -1。"""
    handle: w32.win32base.HANDLE = w32.win32file.CreateFileA(
        path, w32.win32file.GENERIC_READ, w32.win32file.FILE_SHARE_READ,
        t.CPtr(0), w32.win32file.OPEN_EXISTING, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)
    )
    if handle == w32.win32base.INVALID_HANDLE_VALUE:
        return -1
    li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
    result: BOOL = w32.win32file.GetFileSizeEx(handle, t.CPtr(c.Addr(li)))
    w32.win32base.CloseHandle(handle)
    if result == 0:
        return -1
    return li.QuadPart


# =============================================================================
# 工作目录
# =============================================================================

def getcwd() -> str:
    """返回当前工作目录（通过 _mbuddy 分配内存）"""
    buf: bytes = _mbuddy.alloc(MAX_PATH_LEN + 1)
    if buf == None: return None
    length: ULONG = w32.win32file.GetCurrentDirectoryA(MAX_PATH_LEN + 1, buf)
    if length == 0:
        return None
    if length > MAX_PATH_LEN:
        # 缓冲区不够，重新分配
        buf2: bytes = _mbuddy.alloc(length + 1)
        if buf2 == None: return None
        w32.win32file.GetCurrentDirectoryA(length + 1, buf2)
        buf2[length] = 0
        return str(buf2)
    buf[length] = 0
    return str(buf)


def chdir(path: str) -> int:
    """切换当前工作目录。成功返回 0，失败返回 -1。"""
    result: BOOL = w32.win32file.SetCurrentDirectoryA(path)
    if result == 0:
        return -1
    return 0


# =============================================================================
# 文件/目录操作
# =============================================================================

def mkdir(path: str) -> int:
    """创建目录。成功返回 0，失败返回 -1。"""
    result: BOOL = w32.win32file.CreateDirectoryA(path, t.CPtr(0))
    if result == 0:
        return -1
    return 0


def remove(path: str) -> int:
    """删除文件。成功返回 0，失败返回 -1。"""
    result: BOOL = w32.win32file.DeleteFileA(path)
    if result == 0:
        return -1
    return 0


def rmdir(path: str) -> int:
    """删除空目录。成功返回 0，失败返回 -1。"""
    result: BOOL = w32.win32file.RemoveDirectoryA(path)
    if result == 0:
        return -1
    return 0


def rename(old_path: str, new_path: str) -> int:
    """重命名/移动文件或目录。成功返回 0，失败返回 -1。"""
    result: BOOL = w32.win32file.MoveFileExA(
        old_path, new_path,
        w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED
    )
    if result == 0:
        return -1
    return 0


def chmod(path: str, mode: int) -> int:
    """修改文件属性（Windows 简化版：只处理只读位）。
    mode 的 S_IWUSR 位（0o200）为 0 时设为只读，为 1 时设为可写。
    成功返回 0，失败返回 -1。"""
    if (mode & 0o200) != 0:
        # 可写：清除只读属性
        result: BOOL = w32.win32file.SetFileAttributesA(
            path, w32.win32file.FILE_ATTRIBUTE_NORMAL
        )
    else:
        # 只读：设置只读属性
        result: BOOL = w32.win32file.SetFileAttributesA(
            path, w32.win32file.FILE_ATTRIBUTE_READONLY
        )
    if result == 0:
        return -1
    return 0


# =============================================================================
# 目录列举（FindFirstFile / FindNextFile）
# =============================================================================

def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
    """列举目录下的文件/子目录名。
    out_names 为调用者提供的字符串指针数组（char**），每个元素指向一个文件名。
    文件名通过 _mbuddy 分配内存。
    max_count 为 out_names 数组最大容量。
    返回实际列举的条目数。失败返回 0。"""
    # 构造搜索模式：path\*
    path_len: t.CSizeT = len(path)
    pattern: bytes = _mbuddy.alloc(path_len + 3)
    if pattern == None: return 0
    i: t.CSizeT = 0
    for ch in path:
        pattern[i] = ch
        i += 1
    # 添加 \* 后缀
    if path[path_len - 1] != '\\' and path[path_len - 1] != '/':
        pattern[i] = '\\'
        i += 1
    pattern[i] = '*'
    i += 1
    pattern[i] = 0

    find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA()
    handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data)))
    if handle == w32.win32base.INVALID_HANDLE_VALUE:
        return 0

    count: ULONG = 0
    while count < max_count:
        # 跳过 . 和 ..
        name: str = find_data.cFileName
        if name[0] == '.':
            if name[1] == 0:
                # "."
                if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
                    break
                continue
            if name[1] == '.' and name[2] == 0:
                # ".."
                if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
                    break
                continue

        # 复制文件名到新分配的内存
        name_len: t.CSizeT = len(name)
        name_buf: bytes = _mbuddy.alloc(name_len + 1)
        if name_buf == None: break
        j: t.CSizeT = 0
        for ch in name:
            name_buf[j] = ch
            j += 1
        name_buf[name_len] = 0
        out_names[count] = str(name_buf)
        count += 1

        if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
            break

    w32.win32file.FindClose(handle)
    return count


# =============================================================================
# 命令执行
# =============================================================================

def system(cmd: str) -> int:
    """执行命令行命令（通过 C 运行时 system()）。
    命令输出直接到子进程的终端（继承父进程 stdout/stderr）。
    返回命令的退出码（0 表示成功）。"""
    return stdlib.system(cmd)
