#include <math.h>
#include <stdio.h>
#include <windows.h>
#include "mavka/prystriy.h"

логічне (*користувацький_пристрій_мавки_читати_кд)(природне розмір_перед,
                                                   п8* дані_перед,
                                                   природне* вихід_розміру,
                                                   п8** вихід_даних,
                                                   природне дозволити_історію,
                                                   природне* кінець_файлу) =
    NULL;

void out_utf8_data(п8* дані, природне розмір) {
  if (розмір == 0) {
    return;
  }

  // Convert UTF-8 to UTF-16 for Windows
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані, розмір, NULL, 0);
  if (широких_символів == 0) {
    return;
  }

  WCHAR* широкий_буфер =
      (WCHAR*)HeapAlloc(GetProcessHeap(), 0, широких_символів * sizeof(WCHAR));
  if (!широкий_буфер) {
    return;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані, розмір, широкий_буфер,
                      широких_символів);

  // Write to console using Windows API
  HANDLE консоль = GetStdHandle(STD_OUTPUT_HANDLE);
  DWORD записано;
  WriteConsoleW(консоль, широкий_буфер, широких_символів, &записано, NULL);

  HeapFree(GetProcessHeap(), 0, широкий_буфер);
}

void out_utf8_string(char* дані) {
  if (!дані) {
    return;
  }

  // Calculate string length
  природне довжина = 0;
  while (дані[довжина] != '\0') {
    довжина++;
  }

  out_utf8_data((п8*)дані, довжина);
}

extern логічне пристрій_мавки_отримати_версію(природне* вихід_розміру,
                                              п8** вихід_даних) {
  char* версія_ю8 = MAVKA_VERSION;

  природне довжина_версії_ю8 = 0;
  while (версія_ю8[довжина_версії_ю8] != '\0') {
    довжина_версії_ю8++;
  }

  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_ю8_в_кд(довжина_версії_ю8, (п8*)версія_ю8,
                                          вихід_розміру, вихід_даних,
                                          &позиція_помилки)) {
    return TRUE;
  }

  return FALSE;
}

extern void пристрій_мавки_вивести_формат(природне значення) {
  HANDLE консоль = GetStdHandle(STD_OUTPUT_HANDLE);

  // Enable virtual terminal processing for ANSI color support
  DWORD режим;
  if (GetConsoleMode(консоль, &режим)) {
    SetConsoleMode(консоль, режим | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  }

  WORD атрибути;
  switch (значення) {
    case 0: // ФОчистити - reset to default
      атрибути = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
      break;
    case 1: // ФКолірТекстуЧервоний
      атрибути = FOREGROUND_RED | FOREGROUND_INTENSITY;
      break;
    case 2: // ФКолірТекстуЗелений
      атрибути = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
      break;
    case 3: // ФКолірТекстуСиній
      атрибути = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
      break;
    case 4: // ФКолірТекстуЖовтий
      атрибути = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
      break;
    default:
      атрибути = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
      break;
  }

  SetConsoleTextAttribute(консоль, атрибути);
}

extern void пристрій_мавки_вивести_сирі_дані(природне розмір, п8* дані) {
  out_utf8_data(дані, розмір);
}

extern void пристрій_мавки_вивести_кд(природне розмір, п8* дані) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
                                          &позиція_помилки)) {
    out_utf8_data(дані_ю8, розмір_ю8);
    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  } else {
    out_utf8_string("помилка виводу кд\n");
  }
}

extern void пристрій_мавки_надрукувати_кд(природне розмір, п8* дані) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
                                          &позиція_помилки)) {
    out_utf8_data(дані_ю8, розмір_ю8);
    out_utf8_string("\n");
    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  } else {
    out_utf8_string("помилка друку кд\n");
  }
}

extern void пристрій_мавки_вивести_шлях(природне розмір, п8* дані) {
  out_utf8_data(дані, розмір);
}

extern void пристрій_мавки_надрукувати_шлях(природне розмір, п8* дані) {
  out_utf8_data(дані, розмір);
  out_utf8_string("\n");
}

extern void пристрій_мавки_вивести_ю8(природне розмір, п8* дані) {
  out_utf8_data(дані, розмір);
}

extern void пристрій_мавки_надрукувати_ю8(природне розмір, п8* дані) {
  out_utf8_data(дані, розмір);
  out_utf8_string("\n");
}

extern адреса пристрій_мавки_виділити_сиру_памʼять(природне розмір) {
  HANDLE купа = GetProcessHeap();
  return (адреса)HeapAlloc(купа, 0, розмір);
}

extern адреса пристрій_мавки_перевиділити_сиру_памʼять(адреса значення,
                                                       природне новий_розмір) {
  HANDLE купа = GetProcessHeap();
  if (значення == NULL) {
    return (адреса)HeapAlloc(купа, 0, новий_розмір);
  }
  return (адреса)HeapReAlloc(купа, 0, значення, новий_розмір);
}

extern void пристрій_мавки_звільнити_сиру_памʼять(адреса значення) {
  if (значення != NULL) {
    HANDLE купа = GetProcessHeap();
    HeapFree(купа, 0, значення);
  }
}

extern void пристрій_мавки_вийти(ц32 код_виходу) {
  ExitProcess((UINT)код_виходу);
}

extern логічне пристрій_мавки_прочитати_файл(природне розмір_шляху,
                                             п8* дані_шляху,
                                             природне* вихід_розміру,
                                             п8** вихід_даних) {
  // Convert UTF-8 path to wide char
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, NULL, 0);
  if (широких_символів == 0) {
    return FALSE;
  }

  WCHAR* широкий_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (широких_символів + 1) * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, широкий_шлях,
                      широких_символів);
  широкий_шлях[широких_символів] = L'\0';

  // Open file using Windows API
  HANDLE файл = CreateFileW(широкий_шлях, GENERIC_READ, FILE_SHARE_READ, NULL,
                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

  HeapFree(GetProcessHeap(), 0, широкий_шлях);

  if (файл == INVALID_HANDLE_VALUE) {
    return FALSE;
  }

  // Get file size
  LARGE_INTEGER розмір_файлу;
  if (!GetFileSizeEx(файл, &розмір_файлу)) {
    CloseHandle(файл);
    return FALSE;
  }

  *вихід_розміру = (природне)розмір_файлу.QuadPart;

  // Allocate buffer
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    CloseHandle(файл);
    return FALSE;
  }

  // Read file
  DWORD прочитано;
  if (!ReadFile(файл, *вихід_даних, *вихід_розміру, &прочитано, NULL)) {
    HeapFree(GetProcessHeap(), 0, *вихід_даних);
    CloseHandle(файл);
    return FALSE;
  }

  CloseHandle(файл);
  return TRUE;
}

логічне перетворити_п64_в_ю8(п64 значення,
                             природне* вихід_розміру,
                             п8** вихід_даних) {
  char буфер[32];
  int довжина = wsprintfA(буфер, "%I64u", значення);
  if (довжина <= 0) {
    return FALSE;
  }
  *вихід_розміру = (природне)довжина;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    return FALSE;
  }
  for (природне і = 0; і < *вихід_розміру; і++) {
    (*вихід_даних)[і] = (п8)буфер[і];
  }
  return TRUE;
}

логічне перетворити_ц64_в_ю8(ц64 значення,
                             природне* вихід_розміру,
                             п8** вихід_даних) {
  char буфер[32];
  int довжина = wsprintfA(буфер, "%I64d", значення);
  if (довжина <= 0) {
    return FALSE;
  }
  *вихід_розміру = (природне)довжина;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    return FALSE;
  }
  for (природне і = 0; і < *вихід_розміру; і++) {
    (*вихід_даних)[і] = (п8)буфер[і];
  }
  return TRUE;
}

логічне перетворити_р64_в_ю8(р64 значення,
                             природне* вихід_розміру,
                             п8** вихід_даних,
                             ціле* вихід_розміру_експоненти) {
  char буфер[64];
  int довжина;

  // Check for NaN
  if (значення != значення) { // NaN != NaN
    char nan_str[] = "невизначеність";
    *вихід_розміру = sizeof(nan_str) - 1;
    *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
    if (!*вихід_даних)
      return FALSE;
    for (природне і = 0; і < *вихід_розміру; і++) {
      (*вихід_даних)[і] = (п8)nan_str[і];
    }
    *вихід_розміру_експоненти = 0;
    return TRUE;
  }

  // Check for infinity
  if (значення > 1e308 || значення < -1e308) {
    char* inf_str = значення > 0 ? "нескінченність" : "-нескінченність";
    *вихід_розміру = значення > 0 ? sizeof("нескінченність") - 1
                                  : sizeof("-нескінченність") - 1;
    *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
    if (!*вихід_даних)
      return FALSE;
    for (природне і = 0; і < *вихід_розміру; і++) {
      (*вихід_даних)[і] = (п8)inf_str[і];
    }
    *вихід_розміру_експоненти = 0;
    return TRUE;
  }

  довжина = sprintf(буфер, "%.17g", значення);
  if (довжина < 0 || довжина >= (int)sizeof(буфер)) {
    return FALSE;
  }

  // Знаходимо найкоротше представлення, яке round-trips
  // Пробуємо від 15 до 17 цифр точності
  for (int precision = 15; precision <= 17; precision++) {
    довжина = sprintf(буфер, "%.*g", precision, значення);
    if (довжина < 0 || довжина >= (int)sizeof(буфер)) {
      continue;
    }

    // Перевіряємо чи round-trip працює
    р64 parsed = strtod(буфер, NULL);
    if (parsed == значення) {
      break;
    }
  }

  if (довжина < 0 || довжина >= (int)sizeof(буфер)) {
    return FALSE;
  }

  // Find 'e' for exponential notation
  char* e_pos = NULL;
  for (int і = 0; і < довжина; і++) {
    if (буфер[і] == 'e') {
      e_pos = &буфер[і];
      break;
    }
  }

  if (e_pos != NULL) {
    // Parse exponent
    *вихід_розміру_експоненти = 0;
    ціле знак_експоненти = 1;
    char* p = e_pos + 1;
    if (*p == '+') {
      p++;
    } else if (*p == '-') {
      знак_експоненти = -1;
      p++;
    }
    while (*p >= '0' && *p <= '9') {
      *вихід_розміру_експоненти = *вихід_розміру_експоненти * 10 + (*p - '0');
      p++;
    }
    *вихід_розміру_експоненти *= знак_експоненти;

    природне довжина_мантиси = (природне)(e_pos - буфер);

    *вихід_розміру = довжина_мантиси;
    *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
    if (!*вихід_даних)
      return FALSE;

    for (природне і = 0; і < довжина_мантиси; і++) {
      (*вихід_даних)[і] = (п8)буфер[і];
    }
  } else {
    *вихід_розміру_експоненти = 0;

    *вихід_розміру = (природне)довжина;
    *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
    if (!*вихід_даних)
      return FALSE;

    for (природне і = 0; і < *вихід_розміру; і++) {
      (*вихід_даних)[і] = (п8)буфер[і];
    }
  }

  return TRUE;
}

extern логічне пристрій_мавки_перетворити_п64_в_кд(п64 значення,
                                                   природне* вихід_розміру,
                                                   п8** вихід_даних) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_п64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      HeapFree(GetProcessHeap(), 0, дані_ю8);

      return TRUE;
    }

    HeapFree(GetProcessHeap(), 0, дані_ю8);
  }

  return FALSE;
}

extern логічне пристрій_мавки_перетворити_ц64_в_кд(ц64 значення,
                                                   природне* вихід_розміру,
                                                   п8** вихід_даних) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_ц64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      HeapFree(GetProcessHeap(), 0, дані_ю8);

      return TRUE;
    }

    HeapFree(GetProcessHeap(), 0, дані_ю8);
  }

  return FALSE;
}

extern логічне пристрій_мавки_перетворити_р64_в_кд(
    р64 значення,
    природне* вихід_розміру,
    п8** вихід_даних,
    ціле* вихід_розміру_експоненти) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_р64_в_ю8(значення, &розмір_ю8, &дані_ю8,
                           вихід_розміру_експоненти)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      HeapFree(GetProcessHeap(), 0, дані_ю8);

      return TRUE;
    }

    HeapFree(GetProcessHeap(), 0, дані_ю8);
  }

  return FALSE;
}

extern п64 пристрій_мавки_піднести_до_степеня_п64(п64 значення, п64 степінь) {
  п64 результат = 1;
  for (п64 і = 0; і < степінь; і++) {
    результат *= значення;
  }
  return результат;
}

extern ц64 пристрій_мавки_піднести_до_степеня_ц64(ц64 значення, ц64 степінь) {
  ц64 результат = 1;
  for (ц64 і = 0; і < степінь; і++) {
    результат *= значення;
  }
  return результат;
}

extern р64 пристрій_мавки_піднести_до_степеня_р64(р64 значення, р64 степінь) {
  return pow(значення, степінь);
}

extern логічне пристрій_мавки_перевірити_чи_шлях_існує_і_є_файлом(
    природне розмір_шляху,
    п8* дані_шляху) {
  // Convert UTF-8 path to wide char
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, NULL, 0);
  if (широких_символів == 0) {
    return FALSE;
  }

  WCHAR* широкий_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (широких_символів + 1) * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, широкий_шлях,
                      широких_символів);
  широкий_шлях[широких_символів] = L'\0';

  // Get file attributes using Windows API
  DWORD атрибути = GetFileAttributesW(широкий_шлях);
  HeapFree(GetProcessHeap(), 0, широкий_шлях);

  if (атрибути == INVALID_FILE_ATTRIBUTES) {
    return FALSE;
  }

  // Check if it's a regular file (not a directory)
  return (атрибути & FILE_ATTRIBUTE_DIRECTORY) == 0;
}

extern логічне пристрій_мавки_перевірити_чи_шлях_закінчується_як_модуль_мавки(
    природне розмір_шляху,
    п8* дані_шляху) {
  const char* суфікс = ".м";
  природне довжина_суфікса = 0;
  while (суфікс[довжина_суфікса] != '\0') {
    довжина_суфікса++;
  }

  if (розмір_шляху < довжина_суфікса) {
    return FALSE;
  }

  for (природне і = 0; і < довжина_суфікса; і++) {
    if (дані_шляху[розмір_шляху - довжина_суфікса + і] != (п8)суфікс[і]) {
      return FALSE;
    }
  }

  return TRUE;
}

extern логічне пристрій_мавки_отримати_абсолютний_шлях(природне розмір_шляху,
                                                       п8* дані_шляху,
                                                       природне* вихід_розміру,
                                                       п8** вихід_даних) {
  // Convert UTF-8 path to wide char
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, NULL, 0);
  if (широких_символів == 0) {
    return FALSE;
  }

  WCHAR* широкий_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (широких_символів + 1) * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, широкий_шлях,
                      широких_символів);
  широкий_шлях[широких_символів] = L'\0';

  // Get full path using Windows API
  DWORD потрібно = GetFullPathNameW(широкий_шлях, 0, NULL, NULL);
  if (потрібно == 0) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  WCHAR* абсолютний_широкий =
      (WCHAR*)HeapAlloc(GetProcessHeap(), 0, потрібно * sizeof(WCHAR));
  if (!абсолютний_широкий) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  if (GetFullPathNameW(широкий_шлях, потрібно, абсолютний_широкий, NULL) == 0) {
    HeapFree(GetProcessHeap(), 0, абсолютний_широкий);
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  HeapFree(GetProcessHeap(), 0, широкий_шлях);

  // Convert back to UTF-8
  int байтів_ю8 = WideCharToMultiByte(CP_UTF8, 0, абсолютний_широкий, -1, NULL,
                                      0, NULL, NULL);
  if (байтів_ю8 == 0) {
    HeapFree(GetProcessHeap(), 0, абсолютний_широкий);
    return FALSE;
  }

  *вихід_розміру = байтів_ю8 - 1; // Exclude null terminator
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    HeapFree(GetProcessHeap(), 0, абсолютний_широкий);
    return FALSE;
  }

  WideCharToMultiByte(CP_UTF8, 0, абсолютний_широкий, -1, (char*)*вихід_даних,
                      байтів_ю8, NULL, NULL);

  HeapFree(GetProcessHeap(), 0, абсолютний_широкий);
  return TRUE;
}

extern логічне пристрій_мавки_отримати_теку_шляху(природне розмір_шляху,
                                                  п8* дані_шляху,
                                                  природне* вихід_розміру,
                                                  п8** вихід_даних,
                                                  природне рівень) {
  // Convert UTF-8 path to wide char
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, NULL, 0);
  if (широких_символів == 0) {
    return FALSE;
  }

  WCHAR* широкий_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (широких_символів + 1) * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, широкий_шлях,
                      широких_символів);
  широкий_шлях[широких_символів] = L'\0';

  // Find parent directory 'рівень' times
  for (природне і = 0; і < рівень; і++) {
    // Find last backslash or forward slash
    WCHAR* остання_коса = NULL;
    for (int j = широких_символів - 1; j >= 0; j--) {
      if (широкий_шлях[j] == L'\\') {
        остання_коса = &широкий_шлях[j];
        широких_символів = j;
        break;
      }
    }

    if (остання_коса) {
      *остання_коса = L'\0';
    } else {
      // No more parent directories
      break;
    }
  }

  // Convert back to UTF-8
  int байтів_ю8 =
      WideCharToMultiByte(CP_UTF8, 0, широкий_шлях, -1, NULL, 0, NULL, NULL);
  if (байтів_ю8 == 0) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  *вихід_розміру = байтів_ю8 - 1; // Exclude null terminator
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  WideCharToMultiByte(CP_UTF8, 0, широкий_шлях, -1, (char*)*вихід_даних,
                      байтів_ю8 - 1, NULL, NULL);

  HeapFree(GetProcessHeap(), 0, широкий_шлях);
  return TRUE;
}

extern логічне пристрій_мавки_отримати_теку_до_паків(природне розмір_шляху,
                                                     п8* дані_шляху,
                                                     природне* вихід_розміру,
                                                     п8** вихід_даних) {
  const char* паки_суфікс = "\\паки";
  природне довжина_суфікса = 0;
  while (паки_суфікс[довжина_суфікса] != '\0') {
    довжина_суфікса++;
  }

  *вихід_розміру = розмір_шляху + довжина_суфікса;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    return FALSE;
  }

  for (природне і = 0; і < розмір_шляху; і++) {
    (*вихід_даних)[і] = дані_шляху[і];
  }
  for (природне і = 0; і < довжина_суфікса; і++) {
    (*вихід_даних)[розмір_шляху + і] = (п8)паки_суфікс[і];
  }

  return TRUE;
}

extern логічне пристрій_мавки_отримати_назву_модуля_з_шляху(
    природне розмір_шляху,
    п8* дані_шляху,
    природне* вихід_розміру,
    п8** вихід_даних) {
  // Find the last slash or backslash to get basename
  природне позиція_останньої_коси = 0;
  логічне знайдено_косу = FALSE;

  for (природне і = 0; і < розмір_шляху; і++) {
    if (дані_шляху[і] == '\\') {
      позиція_останньої_коси = і + 1;
      знайдено_косу = TRUE;
    }
  }

  // Extract basename
  природне початок_назви = знайдено_косу ? позиція_останньої_коси : 0;
  природне довжина_назви = розмір_шляху - початок_назви;

  // Check and remove ".м" suffix
  const char* суфікс = ".м";
  природне довжина_суфікса = 0;
  while (суфікс[довжина_суфікса] != '\0') {
    довжина_суфікса++;
  }

  if (довжина_назви >= довжина_суфікса) {
    логічне має_суфікс = TRUE;
    for (природне і = 0; і < довжина_суфікса; і++) {
      if (дані_шляху[початок_назви + довжина_назви - довжина_суфікса + і] !=
          (п8)суфікс[і]) {
        має_суфікс = FALSE;
        break;
      }
    }
    if (має_суфікс) {
      довжина_назви -= довжина_суфікса;
    }
  }

  // Create a copy of the name for conversion
  п8* назва_ю8 = (п8*)HeapAlloc(GetProcessHeap(), 0, довжина_назви);
  if (!назва_ю8) {
    return FALSE;
  }

  for (природне і = 0; і < довжина_назви; і++) {
    назва_ю8[і] = дані_шляху[початок_назви + і];
  }

  // Convert UTF-8 to КД encoding
  природне позиція_помилки;
  логічне результат = пристрій_мавки_перекодувати_ю8_в_кд(
      довжина_назви, назва_ю8, вихід_розміру, вихід_даних, &позиція_помилки);

  HeapFree(GetProcessHeap(), 0, назва_ю8);
  return результат;
}

extern логічне пристрій_мавки_збити_шлях_до_модуля(
    природне кількість_елементів,
    ЕлементШляхуПристроюМавки* елементи,
    природне* вихід_розміру,
    п8** вихід_даних) {
  const char* суфікс = ".м";
  природне довжина_суфікса = 0;
  while (суфікс[довжина_суфікса] != '\0') {
    довжина_суфікса++;
  }

  природне загальний_розмір = кількість_елементів - 1 + довжина_суфікса;

  for (природне і = 0; і < кількість_елементів; і++) {
    загальний_розмір += елементи[і].розмір;
  }

  *вихід_розміру = загальний_розмір;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, загальний_розмір);
  if (!*вихід_даних) {
    return FALSE;
  }

  природне позиція = 0;
  for (природне і = 0; і < кількість_елементів; і++) {
    for (природне j = 0; j < елементи[і].розмір; j++) {
      (*вихід_даних)[позиція++] = елементи[і].дані[j];
    }
    if< кількість_елементів - 1) {
      (*вихід_даних)[позиція++] = '\\';
    }
  }

  for (природне і = 0; і < довжина_суфікса; і++) {
    (*вихід_даних)[позиція++] = (п8)суфікс[і];
  }

  return TRUE;
}

extern логічне пристрій_мавки_отримати_відносний_шлях(природне розмір_шляху,
                                                      п8* дані_шляху,
                                                      природне* вихід_розміру,
                                                      п8** вихід_даних) {
  // Convert input path to wide char
  int широких_символів =
      MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, NULL, 0);
  if (широких_символів == 0) {
    return FALSE;
  }

  WCHAR* широкий_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (широких_символів + 1) * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  MultiByteToWideChar(CP_UTF8, 0, (char*)дані_шляху, розмір_шляху, широкий_шлях,
                      широких_символів);
  широкий_шлях[широких_символів] = L'\0';

  // Get current working directory
  DWORD розмір_поточної = GetCurrentDirectoryW(0, NULL);
  if (розмір_поточної == 0) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  WCHAR* поточна_тека =
      (WCHAR*)HeapAlloc(GetProcessHeap(), 0, розмір_поточної * sizeof(WCHAR));
  if (!поточна_тека) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  if (GetCurrentDirectoryW(розмір_поточної, поточна_тека) == 0) {
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  // Get absolute path of the input
  DWORD розмір_абсолютного = GetFullPathNameW(широкий_шлях, 0, NULL, NULL);
  if (розмір_абсолютного == 0) {
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  WCHAR* абсолютний_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, розмір_абсолютного * sizeof(WCHAR));
  if (!абсолютний_шлях) {
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  if (GetFullPathNameW(широкий_шлях, розмір_абсолютного, абсолютний_шлях,
                       NULL) == 0) {
    HeapFree(GetProcessHeap(), 0, абсолютний_шлях);
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  HeapFree(GetProcessHeap(), 0, широкий_шлях);

  // Calculate string lengths
  природне довжина_поточної = 0;
  while (поточна_тека[довжина_поточної] != L'\0') {
    довжина_поточної++;
  }

  природне довжина_абсолютного = 0;
  while (абсолютний_шлях[довжина_абсолютного] != L'\0') {
    довжина_абсолютного++;
  }

  // Find common prefix (comparing case-insensitively for Windows)
  природне спільна_довжина = 0;
  for (природне і = 0; і < довжина_поточної && і < довжина_абсолютного; і++) {
    WCHAR с1 = поточна_тека[і];
    WCHAR с2 = абсолютний_шлях[і];

    // Convert to lowercase for comparison
    if (с1 >= L'A' && с1 <= L'Z')
      с1 += 32;
    if (с2 >= L'A' && с2 <= L'Z')
      с2 += 32;

    // Also treat both / and \ as equivalent
    if ((с1 == L'\\') && (с2 == L'\\')) {
      спільна_довжина = і + 1;
    } else if (с1 == с2) {
      if (с1 == L'\\') {
        спільна_довжина = і + 1;
      }
    } else {
      break;
    }
  }

  // Count how many directories we need to go up
  природне рівнів_вгору = 0;
  for (природне і = спільна_довжина; і < довжина_поточної; і++) {
    if (поточна_тека[і] == L'\\') {
      рівнів_вгору++;
    }
  }
  if (спільна_довжина < довжина_поточної &&
      поточна_тека[довжина_поточної - 1] != L'\\') {
    рівнів_вгору++;
  }

  // Build relative path
  природне розмір_відносного = рівнів_вгору * 3; // "../" for each level up
  if (довжина_абсолютного > спільна_довжина) {
    розмір_відносного += довжина_абсолютного - спільна_довжина;
  } else {
    розмір_відносного = 1; // Just "."
  }

  WCHAR* відносний_шлях = (WCHAR*)HeapAlloc(
      GetProcessHeap(), 0, (розмір_відносного + 1) * sizeof(WCHAR));
  if (!відносний_шлях) {
    HeapFree(GetProcessHeap(), 0, абсолютний_шлях);
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    return FALSE;
  }

  природне позиція = 0;

  // Add "..\" for each level up
  for (природне і = 0; і < рівнів_вгору; і++) {
    відносний_шлях[позиція++] = L'.';
    відносний_шлях[позиція++] = L'.';
    відносний_шлях[позиція++] = L'\\';
  }

  // Add remaining path
  if (довжина_абсолютного > спільна_довжина) {
    for (природне і = спільна_довжина; і < довжина_абсолютного; і++) {
      відносний_шлях[позиція++] = абсолютний_шлях[і];
    }
  } else if (позиція == 0) {
    відносний_шлях[позиція++] = L'.';
  } else if (позиція > 0 && відносний_шлях[позиція - 1] == L'\\') {
    позиція--; // Remove trailing slash
  }

  відносний_шлях[позиція] = L'\0';

  // Convert back to UTF-8
  int байтів_ю8 = WideCharToMultiByte(CP_UTF8, 0, відносний_шлях, позиція, NULL,
                                      0, NULL, NULL);
  if (байтів_ю8 == 0) {
    HeapFree(GetProcessHeap(), 0, відносний_шлях);
    HeapFree(GetProcessHeap(), 0, абсолютний_шлях);
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    return FALSE;
  }

  *вихід_розміру = байтів_ю8;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    HeapFree(GetProcessHeap(), 0, відносний_шлях);
    HeapFree(GetProcessHeap(), 0, абсолютний_шлях);
    HeapFree(GetProcessHeap(), 0, поточна_тека);
    return FALSE;
  }

  WideCharToMultiByte(CP_UTF8, 0, відносний_шлях, позиція, (char*)*вихід_даних,
                      байтів_ю8, NULL, NULL);

  HeapFree(GetProcessHeap(), 0, відносний_шлях);
  HeapFree(GetProcessHeap(), 0, абсолютний_шлях);
  HeapFree(GetProcessHeap(), 0, поточна_тека);
  return TRUE;
}

extern логічне пристрій_мавки_перевірити_чи_шлях_починається_на(
    природне розмір_шляху,
    п8* дані_шляху,
    природне розмір_початку,
    п8* дані_початку) {
  if (розмір_початку > розмір_шляху) {
    return FALSE;
  }

  for (природне і = 0; і < розмір_початку; і++) {
    if (дані_шляху[і] != дані_початку[і]) {
      return FALSE;
    }
  }

  return TRUE;
}

extern логічне пристрій_мавки_отримати_шлях_до_паку_з_шляху_теки_модулів(
    природне розмір_шляху,
    п8* дані_шляху,
    природне розмір_шляху_до_паків,
    п8* дані_шляху_до_паків,
    природне* вихід_розміру,
    п8** вихід_даних) {
  // Check if the module path starts with the packages path
  if (розмір_шляху <= розмір_шляху_до_паків) {
    return FALSE;
  }

  // Verify that the module path starts with the packages path
  for (природне і = 0; і < розмір_шляху_до_паків; і++) {
    if (дані_шляху[і] != дані_шляху_до_паків[і]) {
      return FALSE;
    }
  }

  // Find the next '\\' after the packages path to get the package directory
  природне позиція_наступного_слешу = 0;
  логічне знайдено = FALSE;

  // Skip the packages path and any immediate '\\'
  природне початок = розмір_шляху_до_паків;
  if (початок < розмір_шляху && дані_шляху[початок] == '\\') {
    початок++;
  }

  // Find the next '\\' which marks the end of the package name
  for (природне і = початок; і < розмір_шляху; і++) {
    if (дані_шляху[і] == '\\') {
      позиція_наступного_слешу = і; // Don't include the trailing slash
      знайдено = TRUE;
      break;
    }
  }

  if (!знайдено) {
    позиція_наступного_слешу = розмір_шляху;
  }

  // Return the path up to but not including the trailing slash
  *вихід_розміру = позиція_наступного_слешу;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    return FALSE;
  }

  for (природне і = 0; і < позиція_наступного_слешу; і++) {
    (*вихід_даних)[і] = дані_шляху[і];
  }

  return TRUE;
}

char* read_line_no_newline(size_t* out_len) {
  HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
  if (hStdin == INVALID_HANDLE_VALUE) {
    return NULL;
  }

  // Read wide characters (UTF-16) for proper Unicode support
  size_t wide_cap = 128;
  size_t wide_len = 0;
  WCHAR* wide_buf =
      (WCHAR*)HeapAlloc(GetProcessHeap(), 0, wide_cap * sizeof(WCHAR));
  if (!wide_buf)
    return NULL;

  WCHAR wc;
  DWORD charsRead;

  while (ReadConsoleW(hStdin, &wc, 1, &charsRead, NULL) && charsRead == 1) {
    if (wc == L'\n')
      break; // stop, but DON'T store '\n'

    if (wc == L'\r')
      continue; // skip '\r' in Windows line endings

    if (wide_len + 1 >= wide_cap) {
      wide_cap *= 2;
      WCHAR* tmp = (WCHAR*)HeapReAlloc(GetProcessHeap(), 0, wide_buf,
                                       wide_cap * sizeof(WCHAR));
      if (!tmp) {
        HeapFree(GetProcessHeap(), 0, wide_buf);
        return NULL;
      }
      wide_buf = tmp;
    }

    wide_buf[wide_len++] = wc;
  }

  // If nothing read, return NULL
  if (wide_len == 0) {
    HeapFree(GetProcessHeap(), 0, wide_buf);
    return NULL;
  }

  // Convert UTF-16 to UTF-8
  int utf8_size =
      WideCharToMultiByte(CP_UTF8, 0, wide_buf, wide_len, NULL, 0, NULL, NULL);
  if (utf8_size == 0) {
    HeapFree(GetProcessHeap(), 0, wide_buf);
    return NULL;
  }

  char* buf = (char*)HeapAlloc(GetProcessHeap(), 0, utf8_size + 1);
  if (!buf) {
    HeapFree(GetProcessHeap(), 0, wide_buf);
    return NULL;
  }

  WideCharToMultiByte(CP_UTF8, 0, wide_buf, wide_len, buf, utf8_size, NULL,
                      NULL);
  buf[utf8_size] = '\0';

  HeapFree(GetProcessHeap(), 0, wide_buf);

  if (out_len)
    *out_len = utf8_size;

  return buf;
}

extern логічне пристрій_мавки_читати_кд(природне розмір_перед,
                                        п8* дані_перед,
                                        природне* вихід_розміру,
                                        п8** вихід_даних,
                                        природне дозволити_історію,
                                        природне* кінець_файлу) {
  пристрій_мавки_вивести_кд(розмір_перед, дані_перед);

  size_t len;
  char* data = read_line_no_newline(&len);

  if (!data) {
    *кінець_файлу = TRUE;

    return TRUE;
  }

  *кінець_файлу = FALSE;

  логічне успіх = пристрій_мавки_перекодувати_ю8_в_кд(
      (природне)len, (п8*)data, вихід_розміру, вихід_даних, NULL);

  return успіх;
}

extern логічне пристрій_мавки_отримати_поточний_шлях_процесу(
    природне* вихід_розміру,
    п8** вихід_даних) {
  // Get required buffer size for current directory (in wide chars)
  DWORD розмір = GetCurrentDirectoryW(0, NULL);
  if (розмір == 0) {
    return FALSE;
  }

  // Allocate buffer for wide char path
  WCHAR* широкий_шлях =
      (WCHAR*)HeapAlloc(GetProcessHeap(), 0, розмір * sizeof(WCHAR));
  if (!широкий_шлях) {
    return FALSE;
  }

  // Get current directory as wide char
  if (GetCurrentDirectoryW(розмір, широкий_шлях) == 0) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  // Convert UTF-16 to UTF-8
  int байтів_ю8 =
      WideCharToMultiByte(CP_UTF8, 0, широкий_шлях, -1, NULL, 0, NULL, NULL);
  if (байтів_ю8 == 0) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  // Allocate buffer for UTF-8 (excluding null terminator)
  *вихід_розміру = байтів_ю8 - 1;
  *вихід_даних = (п8*)HeapAlloc(GetProcessHeap(), 0, *вихід_розміру);
  if (!*вихід_даних) {
    HeapFree(GetProcessHeap(), 0, широкий_шлях);
    return FALSE;
  }

  // Convert to UTF-8
  WideCharToMultiByte(CP_UTF8, 0, широкий_шлях, -1, (char*)*вихід_даних,
                      байтів_ю8, NULL, NULL);

  HeapFree(GetProcessHeap(), 0, широкий_шлях);
  return TRUE;
}