#include <windows.h>
#include <tlhelp32.h>

// Function to get process list as a string using a pre-allocated buffer
// Returns the number of bytes written to the buffer (excluding null terminator)
// Returns -1 if the buffer is too small or on error
int GetProcessList(char* buffer, size_t bufferSize) {
    if (!buffer || bufferSize < 1) {
        return -1;
    }
    
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    HANDLE hProcess;
    char szProcessName[MAX_PATH] = "N/A";
    WCHAR architecture[16] = L"Unknown";
    char username[256] = "Unknown";
    
    // Position tracker for buffer
    size_t position = 0;
    
    // Take a snapshot of all processes in the system
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE) {
        return -1;
    }
    
    // Set the size of the structure before using it
    pe32.dwSize = sizeof(PROCESSENTRY32);
    
    // Retrieve information about the first process
    if (!Process32First(hProcessSnap, &pe32)) {
        CloseHandle(hProcessSnap);
        return -1;
    }
    
    // Now walk through the snapshot of processes
    do {
        // Reset variables for each process
        strcpy(szProcessName, pe32.szExeFile);
        wcscpy(architecture, L"Unknown");
        strcpy(username, "Unknown");
        
        // Get a handle to the process
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID);
        if (hProcess != NULL) {
            // Get architecture information
            BOOL isWow64 = FALSE;
            if (IsWow64Process(hProcess, &isWow64)) {
                wcscpy(architecture, isWow64 ? L"x86" : L"x64");
            }
            
            // Get user information
            HANDLE hToken = NULL;
            if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
                DWORD needed = 0;
                TOKEN_USER* pUserInfo = NULL;
                
                GetTokenInformation(hToken, TokenUser, NULL, 0, &needed);
                if (needed > 0) {
                    pUserInfo = (TOKEN_USER*)malloc(needed);
                    if (pUserInfo) {
                        if (GetTokenInformation(hToken, TokenUser, pUserInfo, needed, &needed)) {
                            WCHAR szUserName[256] = L"";
                            WCHAR szDomainName[256] = L"";
                            DWORD dwUserNameSize = 256;
                            DWORD dwDomainNameSize = 256;
                            SID_NAME_USE sidType;
                            
                            LPWSTR stringSid = NULL;
                            if (ConvertSidToStringSidW(pUserInfo->User.Sid, &stringSid)) {
                                if (LookupAccountSidW(NULL, pUserInfo->User.Sid, szUserName, &dwUserNameSize,
                                                     szDomainName, &dwDomainNameSize, &sidType)) {
                                    // Convert wide char to multi-byte for our output
                                    wcstombs(username, szUserName, sizeof(username)-1);
                                }
                                LocalFree(stringSid);
                            }
                        }
                        free(pUserInfo);
                    }
                }
                CloseHandle(hToken);
            }
            
            CloseHandle(hProcess);
        }
        
        // Format for CSV: PID,PPID,Process_Name,Architecture,Username
        char architectureStr[16] = "";
        wcstombs(architectureStr, architecture, sizeof(architectureStr)-1);
        
        char line[MAX_PATH*2] = {0};
        int lineLength = snprintf(line, sizeof(line), "%ld,%ld,%s,%s,%s\n", 
                pe32.th32ProcessID,
                pe32.th32ParentProcessID,
                szProcessName,
                architectureStr,
                username);
        
        // Check if we have enough space in the buffer
        if (position + lineLength >= bufferSize - 1) {
            CloseHandle(hProcessSnap);
            return -1; // Buffer too small
        }
        
        // Add line to buffer
        strcpy(buffer + position, line);
        position += lineLength;
                
    } while (Process32Next(hProcessSnap, &pe32));
    
    CloseHandle(hProcessSnap);
    
    // Ensure null termination
    buffer[position] = '\0';
    return (int)position;
}