// C runtime stubs for freestanding Nim
#include <stddef.h>

void *memcpy(void *dest, const void *src, size_t n) {
    unsigned char *d = dest;
    const unsigned char *s = src;
    while (n--) *d++ = *s++;
    return dest;
}

void *memset(void *s, int c, size_t n) {
    unsigned char *p = s;
    while (n--) *p++ = (unsigned char)c;
    return s;
}

void *memmove(void *dest, const void *src, size_t n) {
    unsigned char *d = dest;
    const unsigned char *s = src;
    if (d < s) {
        while (n--) *d++ = *s++;
    } else {
        d += n;
        s += n;
        while (n--) *--d = *--s;
    }
    return dest;
}

int memcmp(const void *s1, const void *s2, size_t n) {
    const unsigned char *p1 = s1, *p2 = s2;
    while (n--) {
        if (*p1 != *p2) return *p1 - *p2;
        p1++; p2++;
    }
    return 0;
}

size_t strlen(const char *s) {
    size_t len = 0;
    while (*s++) len++;
    return len;
}

char *strcpy(char *dest, const char *src) {
    char *d = dest;
    while ((*d++ = *src++));
    return dest;
}

int strcmp(const char *s1, const char *s2) {
    while (*s1 && (*s1 == *s2)) { s1++; s2++; }
    return *(unsigned char*)s1 - *(unsigned char*)s2;
}

int strncmp(const char *s1, const char *s2, size_t n) {
    while (n && *s1 && (*s1 == *s2)) {
        s1++; s2++; n--;
    }
    if (n == 0) return 0;
    return *(unsigned char*)s1 - *(unsigned char*)s2;
}

char *strncpy(char *dest, const char *src, size_t n) {
    char *d = dest;
    while (n && (*d++ = *src++)) n--;
    while (n--) *d++ = '\0';
    return dest;
}

// abort is used by Nim panic
void abort(void) {
    /* Call Nim panic */
    extern void panic(const char*);
    panic("abort() called");
    while(1) {}
}

/* Stdio stubs - these call into Zig UART */
extern void console_write(const char*, unsigned long);

int puts(const char *s) {
    if (s) {
        unsigned long len = strlen(s);
        console_write(s, len);
        console_write("\n", 1);
    }
    return 0;
}

int putchar(int c) {
    char buf[1] = {(char)c};
    console_write(buf, 1);
    return c;
}

#include <stdarg.h>

void itoa(int n, char s[]) {
    int i, sign;
    if ((sign = n) < 0) n = -n;
    i = 0;
    do { s[i++] = n % 10 + '0'; } while ((n /= 10) > 0);
    if (sign < 0) s[i++] = '-';
    s[i] = '\0';
    // reverse
    for (int j = 0, k = i-1; j < k; j++, k--) {
        char temp = s[j]; s[j] = s[k]; s[k] = temp;
    }
}

int printf(const char *format, ...) {
    va_list args;
    va_start(args, format);
    while (*format) {
        if (*format == '%' && *(format + 1)) {
            format++;
            if (*format == 's') {
                char *s = va_arg(args, char *);
                if (s) console_write(s, strlen(s));
            } else if (*format == 'd') {
                int d = va_arg(args, int);
                char buf[16];
                itoa(d, buf);
                console_write(buf, strlen(buf));
            } else {
                putchar('%');
                putchar(*format);
            }
        } else {
            putchar(*format);
        }
        format++;
    }
    va_end(args);
    return 0;
}

int fprintf(void *stream, const char *format, ...) {
    return printf(format);
}

int vsnprintf(char *str, size_t size, const char *format, va_list args) {
    size_t count = 0;
    if (size == 0) return 0;
    
    while (*format && count < size - 1) {
        if (*format == '%' && *(format + 1)) {
            format++;
            if (*format == 's') {
                char *s = va_arg(args, char *);
                if (s) {
                    while (*s && count < size - 1) {
                        str[count++] = *s++;
                    }
                }
            } else if (*format == 'd' || *format == 'i') {
                int d = va_arg(args, int);
                char buf[16];
                itoa(d, buf);
                char *b = buf;
                while (*b && count < size - 1) {
                    str[count++] = *b++;
                }
            } else {
                str[count++] = '%';
                if (count < size - 1) str[count++] = *format;
            }
        } else {
            str[count++] = *format;
        }
        format++;
    }
    str[count] = '\0';
    return count;
}

int snprintf(char *str, size_t size, const char *format, ...) {
    va_list args;
    va_start(args, format);
    int ret = vsnprintf(str, size, format, args);
    va_end(args);
    return ret;
}

int fflush(void *stream) {
    return 0;
}

unsigned long fwrite(const void *ptr, unsigned long size, unsigned long nmemb, void *stream) {
    console_write(ptr, size * nmemb);
    return nmemb;
}

/* Signal stubs - no signals in freestanding */
typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler) {
    (void)signum;
    (void)handler;
    return (sighandler_t)0;
}

int raise(int sig) {
    (void)sig;
    return 0;
}

/* Exit stubs */
void exit(int status) {
    extern void panic(const char*);
    panic("exit() called - system halt");
    while(1) {}
}

void _Exit(int status) {
    exit(status);
}

int atoi(const char *nptr) {
    int res = 0;
    while (*nptr >= '0' && *nptr <= '9') {
        res = res * 10 + (*nptr - '0');
        nptr++;
    }
    return res;
}

int sprintf(char *str, const char *format, ...) {
    va_list args;
    va_start(args, format);
    // Unsafe sprintf limit
    int ret = vsnprintf(str, 2048, format, args);
    va_end(args);
    return ret;
}

double strtod(const char *nptr, char **endptr) {
    if (endptr) *endptr = (char*)nptr + strlen(nptr); // Fake endptr
    return (double)atoi(nptr);
}

// qsort uses existing memcpy

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
    // Bubble sort for simplicity (O(n^2))
    if (nmemb < 2) return;
    char *b = (char *)base;
    char tmp[256]; // Max item size 256 bytes for swap
    // Verify size? If size > 256, we fail or use loop.
    // mu_Container* is pointer size (8).
    
    for (size_t i = 0; i < nmemb - 1; i++) {
        for (size_t j = 0; j < nmemb - i - 1; j++) {
            char *p1 = b + j * size;
            char *p2 = b + (j + 1) * size;
            if (compar(p1, p2) > 0) {
                // Swap
                if (size <= 256) {
                    memcpy(tmp, p1, size);
                    memcpy(p1, p2, size);
                    memcpy(p2, tmp, size);
                }
            }
        }
    }
}

int errno = 0;
