import t, c
from stdint import *


# =============================================================================
# POSIX Type Alias
# Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here.
# =============================================================================
DIR:       t.CTypedef = t.CVoid | t.CPtr        # Opaque directory stream handle
mode_t:    t.CTypedef = t.CUInt32T              # File mode/permission bits
pid_t:     t.CTypedef = t.CInt32T               # Process ID
off_t:     t.CTypedef = t.CInt64T               # File offset (Linux x86_64)
dev_t:     t.CTypedef = t.CUInt64T              # Device number
ino_t:     t.CTypedef = t.CUInt64T              # inode number
nlink_t:   t.CTypedef = t.CUInt64T              # Hard link count
uid_t:     t.CTypedef = t.CUInt32T              # User ID
gid_t:     t.CTypedef = t.CUInt32T              # Group ID
blksize_t: t.CTypedef = t.CInt64T               # File I/O block size
blkcnt_t:  t.CTypedef = t.CInt64T               # Allocated block count
time_t:    t.CTypedef = t.CInt64T               # Calendar time seconds


# =============================================================================
# open() Flags
# =============================================================================
O_RDONLY:   t.CDefine = 0
O_WRONLY:   t.CDefine = 1
O_RDWR:     t.CDefine = 2
O_CREAT:    t.CDefine = 0o100
O_EXCL:     t.CDefine = 0o200
O_TRUNC:    t.CDefine = 0o1000
O_APPEND:   t.CDefine = 0o2000
O_NONBLOCK: t.CDefine = 0o4000
O_CLOEXEC:  t.CDefine = 0o2000000


# =============================================================================
# access() Test Flags
# =============================================================================
F_OK: t.CDefine = 0    # File exists
R_OK: t.CDefine = 4    # Read permission
W_OK: t.CDefine = 2    # Write permission
X_OK: t.CDefine = 1    # Execute permission


# =============================================================================
# stat struct st_mode Mask and Type Bits
# =============================================================================
S_IFMT:   t.CDefine = 0o170000   # Type mask bits
S_IFSOCK: t.CDefine = 0o140000   # Socket
S_IFLNK:  t.CDefine = 0o120000   # Symbolic link
S_IFREG:  t.CDefine = 0o100000   # Regular file
S_IFBLK:  t.CDefine = 0o060000   # Block device
S_IFDIR:  t.CDefine = 0o040000   # Directory
S_IFCHR:  t.CDefine = 0o020000   # Character device
S_IFIFO:  t.CDefine = 0o010000   # FIFO/pipe

# Permission Bits
S_ISUID: t.CDefine = 0o4000    # Set-user-ID
S_ISGID: t.CDefine = 0o2000    # Set-group-ID
S_ISVTX: t.CDefine = 0o1000    # Sticky bit
S_IRWXU: t.CDefine = 0o700     # Read/write/execute permission
S_IRUSR: t.CDefine = 0o400     # User read permission
S_IWUSR: t.CDefine = 0o200     # User write permission
S_IXUSR: t.CDefine = 0o100     # User execute permission
S_IRWXG: t.CDefine = 0o070     # Read/write/execute permission
S_IRGRP: t.CDefine = 0o040     # Read permission
S_IWGRP: t.CDefine = 0o020     # Write
S_IXGRP: t.CDefine = 0o010     # Execute
S_IRWXO: t.CDefine = 0o007     # Read/write/execute permission
S_IROTH: t.CDefine = 0o004     # Other read permission
S_IWOTH: t.CDefine = 0o002     # Other write permission
S_IXOTH: t.CDefine = 0o001     # Other execute permission


# =============================================================================
# lseek() whence values
# =============================================================================
SEEK_SET: t.CDefine = 0
SEEK_CUR: t.CDefine = 1
SEEK_END: t.CDefine = 2


# =============================================================================
# Path/name length limits
# =============================================================================
PATH_MAX: t.CDefine = 4096
NAME_MAX: t.CDefine = 255


# =============================================================================
# sysconf() parameters
# =============================================================================
_SC_NPROCESSORS_ONLN: t.CDefine = 84
_SC_PAGESIZE:         t.CDefine = 30
_SC_CLK_TCK:          t.CDefine = 2


# =============================================================================
# dirent struct d_type values
# =============================================================================
DT_UNKNOWN: t.CDefine = 0
DT_FIFO:    t.CDefine = 1
DT_CHR:     t.CDefine = 2
DT_DIR:     t.CDefine = 4
DT_BLK:     t.CDefine = 6
DT_REG:     t.CDefine = 8
DT_LNK:     t.CDefine = 10
DT_SOCK:    t.CDefine = 12
DT_WHT:     t.CDefine = 14


# =============================================================================
# waitpid() options
# =============================================================================
WNOHANG:    t.CDefine = 1
WUNTRACED:  t.CDefine = 2
WCONTINUED: t.CDefine = 8


# =============================================================================
# Struct: Linux x86_64 Layout
# =============================================================================

# struct stat (144 bytes, Linux x86_64 glibc layout)
# Note: st_atim/st_mtim/st_ctim in C are struct timespec { tv_sec; tv_nsec; }
# Here split into _sec/_nsec two LONGLONG fields to maintain binary compatibility
class Stat():
    st_dev:       dev_t         # @ 0
    st_ino:       ino_t         # @ 8
    st_nlink:     nlink_t       # @ 16
    st_mode:      mode_t        # @ 24
    st_uid:       uid_t         # @ 28
    st_gid:       gid_t         # @ 32
    __pad0:       INT           # @ 36
    st_rdev:      dev_t         # @ 40
    st_size:      off_t         # @ 48
    st_blksize:   blksize_t     # @ 56
    st_blocks:    blkcnt_t      # @ 64
    st_atim_sec:  time_t        # @ 72
    st_atim_nsec: LONGLONG      # @ 80
    st_mtim_sec:  time_t        # @ 88
    st_mtim_nsec: LONGLONG      # @ 96
    st_ctim_sec:  time_t        # @ 104
    st_ctim_nsec: LONGLONG      # @ 112
    __unused0:    LONGLONG      # @ 120
    __unused1:    LONGLONG      # @ 128
    __unused2:    LONGLONG      # @ 136


# struct dirent (Linux x86_64, d_name is char[256])
# Note: d_name is actually a fixed-length char[256], TransPyC uses CHARPTR as a placeholder (8 bytes).
# Users usually access it via the read-only pointer returned by readdir, not by directly allocating a Dirent structure.
class Dirent():
    d_ino:    ino_t            # @ 0
    d_off:    off_t            # @ 8
    d_reclen: USHORT           # @ 16
    d_type:   BYTE             # @ 18
    d_name:   CHARPTR          # @ 19 (actually char[256], this is a placeholder)


# =============================================================================
# File operations (10)
# =============================================================================
def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass
def close(fd: INT) -> INT | t.State: pass
def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass
def unlink(path: t.CConst | str) -> INT | t.State: pass
def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass
def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass
def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass
def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass


# =============================================================================
# stat series (2)
# =============================================================================
def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass
def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass


# =============================================================================
# Directory operations (6)
# =============================================================================
def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass
def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass
def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass
def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass
def rmdir(path: t.CConst | str) -> INT | t.State: pass
def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass
def chdir(path: t.CConst | str) -> INT | t.State: pass


# =============================================================================
# Process operations (8)
# =============================================================================
def fork() -> pid_t | t.State: pass
def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass
def pipe(fds: INT | t.CPtr) -> INT | t.State: pass
def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass
def _exit(status: INT) -> t.CVoid | t.State: pass
def getpid() -> pid_t | t.State: pass


# =============================================================================
# Environment operations (4)
# =============================================================================
def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass
def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass
def sysconf(name: INT) -> LONG | t.State: pass
def isatty(fd: INT) -> INT | t.State: pass


# =============================================================================
# Inline macros (C macros, implemented as normal functions, not marked as t.CExtern)
# =============================================================================

# st_mode type determination
def S_ISREG(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFREG


def S_ISDIR(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFDIR


def S_ISLNK(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFLNK


def S_ISCHR(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFCHR


def S_ISBLK(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFBLK


def S_ISFIFO(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFIFO


def S_ISSOCK(mode: mode_t) -> bool:
    return (mode & S_IFMT) == S_IFSOCK


# waitpid status parsing
def WIFEXITED(status: INT) -> bool:
    return (status & 0x7F) == 0


def WEXITSTATUS(status: INT) -> INT:
    return (status >> 8) & 0xFF


def WIFSIGNALED(status: INT) -> bool:
    return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F)


def WTERMSIG(status: INT) -> INT:
    return status & 0x7F
