#include "./galloc.c"
#include "mavka/prystriy.h"

size_t strlen(const char* str);
char* dirname(char* path);
char* strrchr(const char* s, int c);
char* strdup(const char* s);
void* memcpy(void* restrict dest, const void* restrict src, size_t n);
char* basename(char* path);

size_t strlen(const char* str) {
  size_t len = 0;
  while (str[len] != '\0') {
    len++;
  }
  return len;
}

char* dirname(char* path) {
  static char dot[] = ".";
  size_t len;

  // Return "." if path is NULL or an empty string
  if (path == NULL || *path == '\0') {
    return dot;
  }

  len = strlen(path);

  // Strip trailing slashes, but don't strip the leading slash if it's the only one
  while (len > 1 && path[len - 1] == '/') {
    path[--len] = '\0';
  }

  // If the path was just slashes (e.g., "///"), it's now "/"
  if (len == 1 && path[0] == '/') {
    return path;
  }

  // Find the last remaining slash
  char* last_slash = strrchr(path, '/');

  if (last_slash != NULL) {
    if (last_slash == path) {
      // Path is something like "/usr", dirname is "/"
      path[1] = '\0';
    } else {
      // Path is something like "/usr/bin", dirname is "/usr"
      *last_slash = '\0';
    }
    return path;
  }

  // No slashes remaining, so it's a relative file in the current directory
  return dot;
}

char* strrchr(const char* s, int c) {
  char* last = NULL;
  // The C standard specifies that 'c' is converted to 'unsigned char'
  unsigned char ch = (unsigned char)c;

  // Loop including the null terminator to handle searching for '\0' natively
  for (;;) {
    if ((unsigned char)*s == ch) {
      last = (char*)s;
    }
    if (*s == '\0') {
      break;
    }
    s++;
  }

  return last;
}

char* strdup(const char* s) {
  if (s == NULL) {
    return NULL;
  }

  // 1. Calculate the length of the string
  size_t len = strlen(s);

  // 2. Allocate memory ( +1 byte for the null terminator '\0' )
  char* dup = (char*)malloc(len + 1);

  // 3. Check if malloc failed (out of memory)
  if (dup == NULL) {
    return NULL;
  }

  // 4. Copy the string contents into the new memory block
  memcpy(dup, s, len + 1);

  return dup;
}

void* memcpy(void* restrict dest, const void* restrict src, size_t n) {
  // Cast the void pointers to unsigned char pointers so we can operate byte-by-byte
  unsigned char* d = (unsigned char*)dest;
  const unsigned char* s = (const unsigned char*)src;

  // Loop through and copy each byte
  for (size_t i = 0; i < n; i++) {
    d[i] = s[i];
  }

  // The standard specifies that memcpy always returns the original dest pointer
  return dest;
}

char* basename(char* path) {
  static char dot[] = ".";
  size_t len;

  // 1. If path is NULL or an empty string, return "."
  if (path == NULL || *path == '\0') {
    return dot;
  }

  len = strlen(path);

  // 2. Strip trailing slashes, but keep the first slash if it's the only one
  while (len > 1 && path[len - 1] == '/') {
    path[--len] = '\0';
  }

  // 3. If the path was entirely slashes (e.g., "///"), it's now "/"
  if (len == 1 && path[0] == '/') {
    return path;
  }

  // 4. Find the last remaining slash
  char* last_slash = strrchr(path, '/');

  // 5. If a slash is found, the component is everything after it
  if (last_slash != NULL) {
    return last_slash + 1;
  }

  // 6. If no slash is found, the entire string is the basename
  return path;
}

#include "../unix_wasm/prystriy_unix_wasm64.c"