#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#define MAX_PATH_LEN 1024
#define MAX_FILES 4096
#define MAX_HASH_ENTRIES 512

// ============================================================================
// Arena Allocator
// ============================================================================

typedef struct
{
    char*  base;
    size_t size;
    size_t offset;
} Arena;

static Arena g_Arena;

static void ArenaInit(size_t size)
{
    g_Arena.base = (char*)malloc(size);
    assert(g_Arena.base != NULL);
    g_Arena.size   = size;
    g_Arena.offset = 0;
}

static void* ArenaPush(size_t size)
{
    // align to 8 bytes
    size_t aligned_size = (size + 7) & ~7;
    if (g_Arena.offset + aligned_size > g_Arena.size)
    {
        printf("[ERROR] Arena out of memory!\n");
        exit(1);
    }
    void* ptr = g_Arena.base + g_Arena.offset;
    g_Arena.offset += aligned_size;
    memset(ptr, 0, size);
    return ptr;
}

// ============================================================================
// String helpers
// ============================================================================

static bool StringContains(const char* haystack, const char* needle)
{
    return strstr(haystack, needle) != NULL;
}

static bool EndsWithNoCase(const char* str, const char* suffix)
{
    int strLen = (int)strlen(str);
    int sufLen = (int)strlen(suffix);
    if (sufLen > strLen) return false;
    return _stricmp(str + strLen - sufLen, suffix) == 0;
}

// ============================================================================
// File I/O helpers
// ============================================================================

typedef struct
{
    char* Data;
    long  Size;
} FileContent;

static FileContent ReadEntireFile(const char* path)
{
    FileContent result = { NULL, 0 };
    FILE*       f      = NULL;
    fopen_s(&f, path, "rb");
    if (!f) return result;

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fseek(f, 0, SEEK_SET);

    if (size > 0)
    {
        result.Data = (char*)ArenaPush(size + 1);
        result.Size = size;
        fread(result.Data, 1, size, f);
        result.Data[size] = '\0';
    }
    fclose(f);
    return result;
}

static bool WriteEntireFile(const char* path, const char* data, long size)
{
    FILE* f = NULL;
    fopen_s(&f, path, "wb");
    if (!f) return false;
    size_t written = fwrite(data, 1, size, f);
    fclose(f);
    return written == (size_t)size;
}

static bool FileExists(const char* path)
{
    DWORD attribs = GetFileAttributesA(path);
    return (attribs != INVALID_FILE_ATTRIBUTES) && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
}

static bool DirectoryExists(const char* path)
{
    DWORD attribs = GetFileAttributesA(path);
    return (attribs != INVALID_FILE_ATTRIBUTES) && (attribs & FILE_ATTRIBUTE_DIRECTORY);
}

static void EnsureDirectoryExists(const char* path)
{
    CreateDirectoryA(path, NULL);
}

static int64_t GetFileModTimeInt64(const char* path)
{
    WIN32_FILE_ATTRIBUTE_DATA data;
    if (GetFileAttributesExA(path, GetFileExInfoStandard, &data))
    {
        ULARGE_INTEGER li;
        li.LowPart  = data.ftLastWriteTime.dwLowDateTime;
        li.HighPart = data.ftLastWriteTime.dwHighDateTime;
        return (int64_t)li.QuadPart;
    }
    return 0;
}

// ============================================================================
// FNV-1a hash
// ============================================================================

static uint64_t ComputeFnv1aHash(const char* data, long size)
{
    uint64_t hash = 14695981039346656037ULL;
    for (long i = 0; i < size; i++)
    {
        hash ^= (uint64_t)(unsigned char)data[i];
        hash *= 1099511628211ULL;
    }
    return hash;
}

// ============================================================================
// Hash cache
// ============================================================================

typedef struct
{
    char Path[MAX_PATH_LEN];
    char HashStr[32];
} HashEntry;

typedef struct
{
    HashEntry* Entries;
    int        Count;
} HashCache;

static HashCache* CreateHashCache()
{
    HashCache* cache = (HashCache*)ArenaPush(sizeof(HashCache));
    cache->Entries   = (HashEntry*)ArenaPush(sizeof(HashEntry) * MAX_HASH_ENTRIES);
    cache->Count     = 0;
    return cache;
}

static const char* HashCacheFind(const HashCache* cache, const char* path)
{
    for (int i = 0; i < cache->Count; i++)
    {
        if (strcmp(cache->Entries[i].Path, path) == 0)
        {
            return cache->Entries[i].HashStr;
        }
    }
    return NULL;
}

static void HashCacheAdd(HashCache* cache, const char* path, const char* hash)
{
    if (cache->Count < MAX_HASH_ENTRIES)
    {
        strncpy_s(cache->Entries[cache->Count].Path, MAX_PATH_LEN, path, _TRUNCATE);
        strncpy_s(cache->Entries[cache->Count].HashStr, 32, hash, _TRUNCATE);
        cache->Count++;
    }
}

static void LoadHashCache(const char* cachePath, HashCache* cache)
{
    FileContent content = ReadEntireFile(cachePath);
    if (!content.Data) return;

    const char* pos = content.Data;
    while (*pos != '\0')
    {
        const char* lineStart = pos;
        while (*pos != '\0' && *pos != '\n' && *pos != '\r')
            pos++;
        int lineLen = (int)(pos - lineStart);

        if (lineLen > 0)
        {
            const char* sep = NULL;
            for (const char* c = lineStart; c < lineStart + lineLen; c++)
            {
                if (*c == '=')
                {
                    sep = c;
                    break;
                }
            }
            if (sep)
            {
                char key[MAX_PATH_LEN] = { 0 };
                int  keyLen            = (int)(sep - lineStart);
                if (keyLen >= MAX_PATH_LEN) keyLen = MAX_PATH_LEN - 1;
                memcpy(key, lineStart, keyLen);

                int  valLen  = (int)((lineStart + lineLen) - (sep + 1));
                char val[32] = { 0 };
                if (valLen > 0 && valLen < 32)
                {
                    memcpy(val, sep + 1, valLen);
                }
                HashCacheAdd(cache, key, val);
            }
        }
        while (*pos == '\n' || *pos == '\r')
            pos++;
    }
}

static void SaveHashCache(const char* cachePath, const HashCache* cache)
{
    long  bufSize = MAX_HASH_ENTRIES * (MAX_PATH_LEN + 32 + 2);
    char* buffer  = (char*)ArenaPush(bufSize);
    int   offset  = 0;

    for (int i = 0; i < cache->Count; i++)
    {
        int written = sprintf_s(buffer + offset, bufSize - offset, "%s=%s\n", cache->Entries[i].Path, cache->Entries[i].HashStr);
        if (written > 0) offset += written;
    }
    WriteEntireFile(cachePath, buffer, offset);
}

// ============================================================================
// Clean #pragma message lines and compute hash for a unity file
// ============================================================================

typedef struct
{
    char HashStr[32];
    bool WasCleaned;
} CleanResult;

static CleanResult CleanAndHashUnityFile(const char* filePath)
{
    CleanResult result  = { { 0 }, false };
    FileContent content = ReadEntireFile(filePath);
    if (!content.Data) return result;

    if (StringContains(content.Data, "#pragma message"))
    {
        char* filtered     = (char*)ArenaPush(content.Size + 1);
        long  filteredSize = 0;

        const char* pos = content.Data;
        while (*pos != '\0')
        {
            const char* lineStart = pos;
            while (*pos != '\0' && *pos != '\n')
                pos++;

            bool skipLine = false;
            for (const char* c = lineStart; c < pos; c++)
            {
                if (c + 15 <= content.Data + content.Size && memcmp(c, "#pragma message", 15) == 0)
                {
                    skipLine = true;
                    break;
                }
            }

            if (!skipLine)
            {
                long lineLen = (long)(pos - lineStart);
                memcpy(filtered + filteredSize, lineStart, lineLen);
                filteredSize += lineLen;
                if (*pos == '\n') filtered[filteredSize++] = '\n';
            }
            if (*pos == '\n') pos++;
        }
        filtered[filteredSize] = '\0';

        WriteEntireFile(filePath, filtered, filteredSize);
        uint64_t hashVal = ComputeFnv1aHash(filtered, filteredSize);
        sprintf_s(result.HashStr, sizeof(result.HashStr), "%llu", hashVal);
        result.WasCleaned = true;
    }
    else
    {
        uint64_t hashVal = ComputeFnv1aHash(content.Data, content.Size);
        sprintf_s(result.HashStr, sizeof(result.HashStr), "%llu", hashVal);
    }
    return result;
}

// ============================================================================
// Recursive directory scan
// ============================================================================

static int64_t GetNewestSourceTimeRecursive(const char* dirPath)
{
    int64_t newest = 0;
    if (!DirectoryExists(dirPath)) return newest;

    char searchPath[MAX_PATH_LEN];
    snprintf(searchPath, sizeof(searchPath), "%s\\*", dirPath);

    WIN32_FIND_DATAA findData;
    HANDLE           hFind = FindFirstFileA(searchPath, &findData);
    if (hFind == INVALID_HANDLE_VALUE) return newest;

    do
    {
        if (findData.cFileName[0] == '.' &&
            (findData.cFileName[1] == '\0' || (findData.cFileName[1] == '.' && findData.cFileName[2] == '\0')))
        {
            continue;
        }

        char fullPath[MAX_PATH_LEN];
        snprintf(fullPath, sizeof(fullPath), "%s\\%s", dirPath, findData.cFileName);

        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            int64_t subNewest = GetNewestSourceTimeRecursive(fullPath);
            if (subNewest > newest) newest = subNewest;
        }
        else
        {
            if (EndsWithNoCase(findData.cFileName, ".cpp") || EndsWithNoCase(findData.cFileName, ".h") ||
                EndsWithNoCase(findData.cFileName, ".hpp") || EndsWithNoCase(findData.cFileName, ".inl") ||
                EndsWithNoCase(findData.cFileName, ".c"))
            {
                ULARGE_INTEGER li;
                li.LowPart  = findData.ftLastWriteTime.dwLowDateTime;
                li.HighPart = findData.ftLastWriteTime.dwHighDateTime;
                int64_t ft  = (int64_t)li.QuadPart;
                if (ft > newest) newest = ft;
            }
        }
    }
    while (FindNextFileA(hFind, &findData));

    FindClose(hFind);
    return newest;
}

// ============================================================================
// Collect unity files
// ============================================================================

typedef struct
{
    char (*Paths)[MAX_PATH_LEN];
    int Count;
} FilePathList;

static FilePathList* CreateFilePathList()
{
    FilePathList* list = (FilePathList*)ArenaPush(sizeof(FilePathList));
    list->Paths        = (char(*)[MAX_PATH_LEN])ArenaPush(MAX_FILES * MAX_PATH_LEN);
    list->Count        = 0;
    return list;
}

static void FilePathListAdd(FilePathList* list, const char* path)
{
    if (list->Count < MAX_FILES)
    {
        strncpy_s(list->Paths[list->Count], MAX_PATH_LEN, path, _TRUNCATE);
        list->Count++;
    }
}

static void CollectUnityFiles(const char* dirPath, FilePathList* list)
{
    char searchPath[MAX_PATH_LEN];
    snprintf(searchPath, sizeof(searchPath), "%s\\*", dirPath);

    WIN32_FIND_DATAA findData;
    HANDLE           hFind = FindFirstFileA(searchPath, &findData);
    if (hFind == INVALID_HANDLE_VALUE) return;

    do
    {
        if (findData.cFileName[0] == '.' &&
            (findData.cFileName[1] == '\0' || (findData.cFileName[1] == '.' && findData.cFileName[2] == '\0')))
        {
            continue;
        }

        char fullPath[MAX_PATH_LEN];
        snprintf(fullPath, sizeof(fullPath), "%s\\%s", dirPath, findData.cFileName);

        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            CollectUnityFiles(fullPath, list);
        }
        else
        {
            if (StringContains(findData.cFileName, "_Unity") && EndsWithNoCase(findData.cFileName, ".cpp"))
            {
                FilePathListAdd(list, fullPath);
            }
        }
    }
    while (FindNextFileA(hFind, &findData));

    FindClose(hFind);
}

// ============================================================================
// Commands
// ============================================================================

typedef struct
{
    char StepName[256];
    char OutputFile[MAX_PATH_LEN];
    char Depends[MAX_PATH_LEN];
    char Command[MAX_FILES];
} BuildStep;

typedef struct
{
    char      Name[64];
    char      FastBuildTargets[512];
    BuildStep Steps[32];
    int       StepCount;
} BuildConfig;

static int ExecuteCmd(const char* cmdLine)
{
    STARTUPINFOA si;
    memset(&si, 0, sizeof(si));
    si.cb                        = sizeof(si);
    PROCESS_INFORMATION pi       = { 0 };
    DWORD               exitCode = 1;

    char* cmdBuf = (char*)ArenaPush(MAX_FILES);
    strcpy_s(cmdBuf, MAX_FILES, cmdLine);

    if (CreateProcessA(NULL, cmdBuf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitCode);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else
    {
        printf("[ERROR] Failed to execute command.\n");
        return 1;
    }
    return (int)exitCode;
}

typedef struct
{
    char    Path[MAX_PATH_LEN];
    int64_t Time;
} DirCacheEntry;

static DirCacheEntry g_DirCache[64];
static int           g_DirCacheCount = 0;

static int64_t GetDirTime(const char* dir)
{
    for (int k = 0; k < g_DirCacheCount; k++)
    {
        if (_stricmp(g_DirCache[k].Path, dir) == 0) return g_DirCache[k].Time;
    }
    int64_t t = GetNewestSourceTimeRecursive(dir);
    if (g_DirCacheCount < 64)
    {
        strncpy_s(g_DirCache[g_DirCacheCount].Path, MAX_PATH_LEN, dir, _TRUNCATE);
        g_DirCache[g_DirCacheCount].Time = t;
        g_DirCacheCount++;
    }
    return t;
}

static char g_TimingsBuf[MAX_FILES * 2];
static int  g_TimingsLen = 0;

static void AppendTiming(const char* stepName, double secs)
{
    g_TimingsLen += sprintf_s(g_TimingsBuf + g_TimingsLen, sizeof(g_TimingsBuf) - g_TimingsLen, "%s|%.3fs\n", stepName, secs);
}

static int CommandRunPlan(int argc, char* argv[])
{
    if (argc < 3)
    {
        printf("[ERROR] Usage: build_system run_plan <plan_file.txt>\n");
        return 1;
    }
    const char* planFile = argv[2];

    FileContent planContent = ReadEntireFile(planFile);
    if (!planContent.Data)
    {
        printf("[ERROR] Could not read build plan: %s\n", planFile);
        return 1;
    }

    EnsureDirectoryExists("Intermediate");
    DeleteFileA("Intermediate\\step_timings.tmp");
    DeleteFileA("Intermediate\\built_outputs.tmp");

    LARGE_INTEGER perfStart, perfEnd, perfFreq;
    QueryPerformanceCounter(&perfStart);
    QueryPerformanceFrequency(&perfFreq);

    // Parse plan file
    BuildConfig configs[4];
    memset(configs, 0, sizeof(configs));
    int configCount = 0;

    const char* pos = planContent.Data;
    while (*pos != '\0')
    {
        const char* lineStart = pos;
        while (*pos != '\0' && *pos != '\n' && *pos != '\r')
            pos++;
        int lineLen = (int)(pos - lineStart);

        if (lineLen > 0)
        {
            if (lineLen > 7 && memcmp(lineStart, "CONFIG ", 7) == 0)
            {
                if (configCount < 4)
                {
                    int nLen = lineLen - 7;
                    if (nLen >= (int)sizeof(configs[configCount].Name)) nLen = (int)sizeof(configs[configCount].Name) - 1;
                    memcpy(configs[configCount].Name, lineStart + 7, nLen);
                    configs[configCount].Name[nLen] = '\0';
                    configCount++;
                }
            }
            else if (configCount > 0)
            {
                BuildConfig* curCfg = &configs[configCount - 1];
                if (lineLen > 10 && memcmp(lineStart, "FASTBUILD ", 10) == 0)
                {
                    int nLen = lineLen - 10;
                    if (nLen >= (int)sizeof(curCfg->FastBuildTargets)) nLen = (int)sizeof(curCfg->FastBuildTargets) - 1;
                    memcpy(curCfg->FastBuildTargets, lineStart + 10, nLen);
                    curCfg->FastBuildTargets[nLen] = '\0';
                }
                else if (lineLen > 5 && memcmp(lineStart, "STEP ", 5) == 0)
                {
                    if (curCfg->StepCount < 32)
                    {
                        int nLen = lineLen - 5;
                        if (nLen >= (int)sizeof(curCfg->Steps[curCfg->StepCount].StepName))
                            nLen = (int)sizeof(curCfg->Steps[curCfg->StepCount].StepName) - 1;
                        memcpy(curCfg->Steps[curCfg->StepCount].StepName, lineStart + 5, nLen);
                        curCfg->Steps[curCfg->StepCount].StepName[nLen] = '\0';
                        curCfg->StepCount++;
                    }
                }
                else if (lineLen > 7 && memcmp(lineStart, "OUTPUT ", 7) == 0 && curCfg->StepCount > 0)
                {
                    int nLen = lineLen - 7;
                    if (nLen >= (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].OutputFile))
                        nLen = (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].OutputFile) - 1;
                    memcpy(curCfg->Steps[curCfg->StepCount - 1].OutputFile, lineStart + 7, nLen);
                    curCfg->Steps[curCfg->StepCount - 1].OutputFile[nLen] = '\0';
                }
                else if (lineLen > 8 && memcmp(lineStart, "DEPENDS ", 8) == 0 && curCfg->StepCount > 0)
                {
                    int nLen = lineLen - 8;
                    if (nLen >= (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].Depends))
                        nLen = (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].Depends) - 1;
                    memcpy(curCfg->Steps[curCfg->StepCount - 1].Depends, lineStart + 8, nLen);
                    curCfg->Steps[curCfg->StepCount - 1].Depends[nLen] = '\0';
                }
                else if (lineLen > 8 && memcmp(lineStart, "COMMAND ", 8) == 0 && curCfg->StepCount > 0)
                {
                    int nLen = lineLen - 8;
                    if (nLen >= (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].Command))
                        nLen = (int)sizeof(curCfg->Steps[curCfg->StepCount - 1].Command) - 1;
                    memcpy(curCfg->Steps[curCfg->StepCount - 1].Command, lineStart + 8, nLen);
                    curCfg->Steps[curCfg->StepCount - 1].Command[nLen] = '\0';
                }
            }
        }
        while (*pos == '\n' || *pos == '\r')
            pos++;
    }

    bool anyBuilt = false;

    for (int i = 0; i < configCount; i++)
    {
        BuildConfig* cfg = &configs[i];
        printf("\n==============================================================================\n");
        printf("Generating Unity Files into Intermediate/ via FASTBuild [%s]...\n", cfg->Name);
        printf("==============================================================================\n");

        if (cfg->FastBuildTargets[0] != '\0')
        {
            char fbuildCmd[MAX_PATH_LEN];
            sprintf_s(fbuildCmd, sizeof(fbuildCmd), "misc\\fbuild.exe %s", cfg->FastBuildTargets);

            LARGE_INTEGER tStart, tEnd;
            QueryPerformanceCounter(&tStart);
            int res = ExecuteCmd(fbuildCmd);
            QueryPerformanceCounter(&tEnd);

            char stepName[MAX_PATH_LEN];
            sprintf_s(stepName, sizeof(stepName), "FASTBuild Unity Gen [%s]", cfg->Name);
            AppendTiming(stepName, (double)(tEnd.QuadPart - tStart.QuadPart) / (double)perfFreq.QuadPart);

            if (res != 0)
            {
                printf("[BUILD FAILED] FASTBuild failed for %s.\n", cfg->Name);
                return res;
            }
        }

        HashCache* oldCache = CreateHashCache();
        LoadHashCache("Intermediate\\.unity_hashes_cache", oldCache);

        HashCache* newCache     = CreateHashCache();
        bool       unityChanged = false;

        FilePathList* unityFiles = CreateFilePathList();
        CollectUnityFiles("Intermediate", unityFiles);

        if (unityFiles->Count == 0)
        {
            unityChanged = true;
        }
        else
        {
            for (int k = 0; k < unityFiles->Count; k++)
            {
                CleanResult cr = CleanAndHashUnityFile(unityFiles->Paths[k]);
                HashCacheAdd(newCache, unityFiles->Paths[k], cr.HashStr);

                const char* oldHash = HashCacheFind(oldCache, unityFiles->Paths[k]);
                if (oldHash == NULL || strcmp(oldHash, cr.HashStr) != 0)
                {
                    unityChanged = true;
                }
            }
        }
        SaveHashCache("Intermediate\\.unity_hashes_cache", newCache);

        if (unityChanged)
        {
            printf("[FASTBuild] Unity structure or source file list changed.\n");
        }
        else
        {
            printf("[FASTBuild] No Unity file structure changes detected [up-to-date].\n");
        }

        printf("\n==============================================================================\n");
        printf("Compiling Targets [%s]...\n", cfg->Name);
        printf("==============================================================================\n");

        g_DirCacheCount   = 0;
        bool anyNeedBuild = false;

        for (int j = 0; j < cfg->StepCount; j++)
        {
            BuildStep*  step    = &cfg->Steps[j];
            int64_t     maxTime = 0;
            const char* cur     = step->Depends;
            while (*cur)
            {
                const char* nextPipe              = strchr(cur, '|');
                char        dirPath[MAX_PATH_LEN] = { 0 };
                if (nextPipe)
                {
                    int dLen = (int)(nextPipe - cur);
                    if (dLen >= (int)sizeof(dirPath)) dLen = (int)sizeof(dirPath) - 1;
                    memcpy(dirPath, cur, dLen);
                    dirPath[dLen] = '\0';
                    cur           = nextPipe + 1;
                }
                else
                {
                    strcpy_s(dirPath, sizeof(dirPath), cur);
                    cur += strlen(cur);
                }
                if (dirPath[0] != '\0')
                {
                    int64_t t = GetDirTime(dirPath);
                    if (t > maxTime) maxTime = t;
                }
            }

            bool needCompile = unityChanged;
            if (!needCompile)
            {
                if (!FileExists(step->OutputFile))
                {
                    needCompile = true;
                }
                else
                {
                    int64_t outTime = GetFileModTimeInt64(step->OutputFile);
                    if (outTime < maxTime) needCompile = true;
                }
            }

            printf("\n--- %s ---\n", step->StepName);
            if (!needCompile)
            {
                printf("[SKIP / UP-TO-DATE] %s [Binary up to date]\n", step->OutputFile);
            }
            else
            {
                printf("[REBUILDING] Compiling %s...\n", step->OutputFile);
                anyNeedBuild = true;

                LARGE_INTEGER tStart, tEnd;
                QueryPerformanceCounter(&tStart);
                int res = ExecuteCmd(step->Command);
                QueryPerformanceCounter(&tEnd);

                AppendTiming(step->StepName, (double)(tEnd.QuadPart - tStart.QuadPart) / (double)perfFreq.QuadPart);

                if (res != 0)
                {
                    printf("[BUILD FAILED] Command failed with exit code %d.\n", res);
                    return res;
                }

                char builtOut[MAX_PATH_LEN + 2];
                sprintf_s(builtOut, sizeof(builtOut), "%s\n", step->OutputFile);

                HANDLE hFile = CreateFileA("Intermediate\\built_outputs.tmp", FILE_APPEND_DATA, FILE_SHARE_READ, NULL,
                                           OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (hFile != INVALID_HANDLE_VALUE)
                {
                    DWORD written = 0;
                    WriteFile(hFile, builtOut, (DWORD)strlen(builtOut), &written, NULL);
                    CloseHandle(hFile);
                }
                anyBuilt = true;
            }
        }

        if (!anyNeedBuild)
        {
            printf("\n[SKIP / UP-TO-DATE] All requested targets in [%s] are up-to-date.\n", cfg->Name);
        }
    }

    if (g_TimingsLen > 0)
    {
        WriteEntireFile("Intermediate\\step_timings.tmp", g_TimingsBuf, g_TimingsLen);
    }

    QueryPerformanceCounter(&perfEnd);
    double elapsedSeconds = (double)(perfEnd.QuadPart - perfStart.QuadPart) / (double)perfFreq.QuadPart;

    char elapsedBuf[64];
    if (elapsedSeconds < 60.0)
    {
        sprintf_s(elapsedBuf, sizeof(elapsedBuf), "%.3fs", elapsedSeconds);
    }
    else
    {
        int totalMs = (int)(elapsedSeconds * 1000.0);
        int hours   = totalMs / 3600000;
        int minutes = (totalMs % 3600000) / 60000;
        int seconds = (totalMs % 60000) / 1000;
        int ms      = totalMs % 1000;
        sprintf_s(elapsedBuf, sizeof(elapsedBuf), "%02d:%02d:%02d.%03d", hours, minutes, seconds, ms);
    }

    printf("\n==============================================================================\n");
    printf("[BUILD SUMMARY]\n");
    printf("==============================================================================\n");

    if (g_TimingsLen > 0)
    {
        printf("Step Timings:\n");
        const char* pos = g_TimingsBuf;
        while (*pos)
        {
            const char* lineStart = pos;
            while (*pos && *pos != '\n')
                pos++;
            int len = (int)(pos - lineStart);
            if (len > 0)
            {
                const char* pipe = strchr(lineStart, '|');
                if (pipe && pipe < pos)
                {
                    char stepName[MAX_PATH_LEN] = { 0 };
                    int  nameLen                = (int)(pipe - lineStart);
                    if (nameLen >= MAX_PATH_LEN) nameLen = MAX_PATH_LEN - 1;
                    memcpy(stepName, lineStart, nameLen);

                    char durStr[64] = { 0 };
                    int  durLen     = (int)(pos - (pipe + 1));
                    if (durLen >= 64) durLen = 63;
                    memcpy(durStr, pipe + 1, durLen);

                    printf("  - %-42s : %s\n", stepName, durStr);
                }
            }
            if (*pos == '\n') pos++;
        }
        printf("------------------------------------------------------------------------------\n");
    }

    printf("Total Duration : %s\n", elapsedBuf);
    printf("Output Binaries:\n");

    if (anyBuilt)
    {
        FileContent outputsContent = ReadEntireFile("Intermediate\\built_outputs.tmp");
        if (outputsContent.Data)
        {
            const char* pos = outputsContent.Data;
            while (*pos)
            {
                const char* lineStart = pos;
                while (*pos && *pos != '\n' && *pos != '\r')
                    pos++;
                int len = (int)(pos - lineStart);
                if (len > 0)
                {
                    char filePath[MAX_PATH_LEN] = { 0 };
                    if (len >= MAX_PATH_LEN) len = MAX_PATH_LEN - 1;
                    memcpy(filePath, lineStart, len);
                    WIN32_FILE_ATTRIBUTE_DATA fileData;
                    if (GetFileAttributesExA(filePath, GetFileExInfoStandard, &fileData))
                    {
                        ULARGE_INTEGER fileSize;
                        fileSize.LowPart  = fileData.nFileSizeLow;
                        fileSize.HighPart = fileData.nFileSizeHigh;
                        double sizeMB     = (double)fileSize.QuadPart / (1024.0 * 1024.0);
                        printf("  - %s (%.2f MB)\n", filePath, sizeMB);
                    }
                }
                while (*pos == '\n' || *pos == '\r')
                    pos++;
            }
        }
        DeleteFileA("Intermediate\\built_outputs.tmp");
    }
    else
    {
        printf("  - None built in this session (all requested targets up-to-date)\n");
    }

    printf("==============================================================================\n");
    printf("[ALL BUILDS SUCCEEDED] All requested targets processed successfully.\n");
    printf("==============================================================================\n");
    fflush(stdout);

    return 0;
}

int main(int argc, char* argv[])
{
    // 256 MB Bump allocator
    ArenaInit(256 * 1024 * 1024);

    if (argc < 2)
    {
        printf("Usage: build_system <command> [args...]\n");
        printf("Commands:\n");
        printf("  run_plan <plan_file>     Run the build from a generated plan file\n");
        printf("  check_alive              Returns 0 immediately to test execution\n");
        return 1;
    }

    const char* cmd = argv[1];
    if (strcmp(cmd, "check_alive") == 0) return 0;
    if (strcmp(cmd, "run_plan") == 0) return CommandRunPlan(argc, argv);

    printf("[ERROR] Unknown command: %s\n", cmd);
    return 1;
}
