// Bootstrap:
//   Windows: cl /nologo build.c
//   macOS:   cc build.c -o build
// After that, just run: ./build (or build.exe on Windows)

#define NOB_IMPLEMENTATION
#include "vendor/nob/nob.h"

////////////////////////////////
// lunasvg/plutovg static library build helpers

static const char *plutovg_sources[] = {
    "vendor/lunasvg/plutovg/source/plutovg-blend.c",
    "vendor/lunasvg/plutovg/source/plutovg-canvas.c",
    "vendor/lunasvg/plutovg/source/plutovg-font.c",
    "vendor/lunasvg/plutovg/source/plutovg-ft-math.c",
    "vendor/lunasvg/plutovg/source/plutovg-ft-raster.c",
    "vendor/lunasvg/plutovg/source/plutovg-ft-stroker.c",
    "vendor/lunasvg/plutovg/source/plutovg-matrix.c",
    "vendor/lunasvg/plutovg/source/plutovg-paint.c",
    "vendor/lunasvg/plutovg/source/plutovg-path.c",
    "vendor/lunasvg/plutovg/source/plutovg-rasterize.c",
    "vendor/lunasvg/plutovg/source/plutovg-surface.c",
};

static const char *lunasvg_sources[] = {
    "vendor/lunasvg/source/graphics.cpp",
    "vendor/lunasvg/source/lunasvg.cpp",
    "vendor/lunasvg/source/svgelement.cpp",
    "vendor/lunasvg/source/svggeometryelement.cpp",
    "vendor/lunasvg/source/svglayoutstate.cpp",
    "vendor/lunasvg/source/svgpaintelement.cpp",
    "vendor/lunasvg/source/svgparser.cpp",
    "vendor/lunasvg/source/svgproperty.cpp",
    "vendor/lunasvg/source/svgrenderstate.cpp",
    "vendor/lunasvg/source/svgtextelement.cpp",
};

////////////////////////////////
// FreeType source files

static const char *freetype_sources[] = {
    "vendor/freetype/src/base/ftsystem.c",
    "vendor/freetype/src/base/ftinit.c",
    "vendor/freetype/src/base/ftdebug.c",
    "vendor/freetype/src/base/ftbase.c",
    "vendor/freetype/src/base/ftbbox.c",
    "vendor/freetype/src/base/ftglyph.c",
    "vendor/freetype/src/base/ftbitmap.c",
    "vendor/freetype/src/base/ftmm.c",
    "vendor/freetype/src/truetype/truetype.c",
    "vendor/freetype/src/sfnt/sfnt.c",
    "vendor/freetype/src/smooth/smooth.c",
    "vendor/freetype/src/autofit/autofit.c",
    "vendor/freetype/src/psnames/psnames.c",
    "vendor/freetype/src/pshinter/pshinter.c",
    "vendor/freetype/src/gzip/ftgzip.c",
};

////////////////////////////////
// Font embedding — reads a .ttf and writes a C header with the data as a byte array

static bool embed_font_file(const char *ttf_path, const char *header_path) {
    if (!nob_needs_rebuild1(header_path, ttf_path)) {
        nob_log(NOB_INFO, "Font header %s is up to date", header_path);
        return true;
    }

    Nob_String_Builder sb = {0};
    if (!nob_read_entire_file(ttf_path, &sb)) return false;

    FILE *out = fopen(header_path, "wb");
    if (!out) {
        nob_log(NOB_ERROR, "Could not open %s for writing", header_path);
        nob_sb_free(sb);
        return false;
    }

    fprintf(out, "// Auto-generated from %s — do not edit\n", ttf_path);
    fprintf(out, "#pragma once\n\n");
    fprintf(out, "static const unsigned char font_inter_data[] = {\n");
    for (size_t i = 0; i < sb.count; i++) {
        if (i % 16 == 0) fprintf(out, "    ");
        fprintf(out, "0x%02x,", (unsigned char)sb.items[i]);
        if (i % 16 == 15 || i == sb.count - 1) fprintf(out, "\n");
    }
    fprintf(out, "};\n\n");
    fprintf(out, "static const unsigned int font_inter_size = %zu;\n", sb.count);

    fclose(out);
    nob_sb_free(sb);
    nob_log(NOB_INFO, "Generated %s (%zu bytes)", header_path, sb.count);
    return true;
}

#ifdef __APPLE__
////////////////////////////////
// macOS build (clang++ with Objective-C++)

static const char *frameworks[] = {
    "-framework", "Metal",
    "-framework", "Cocoa",
    "-framework", "CoreAudio",
    "-framework", "AudioToolbox",
    "-framework", "CoreMIDI",
    "-framework", "QuartzCore",
    "-framework", "CoreFoundation",
};

static bool build_lunasvg_lib(const char *build_dir, bool debug) {
    const char *obj_dir = nob_temp_sprintf("%s/lunasvg_obj", build_dir);
    const char *lib_path = "vendor/lunasvg/liblunasvg.a";

    // Collect all source paths to check if rebuild is needed
    {
        const char *all_sources[NOB_ARRAY_LEN(plutovg_sources) + NOB_ARRAY_LEN(lunasvg_sources)];
        size_t n = 0;
        for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++)
            all_sources[n++] = plutovg_sources[i];
        for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++)
            all_sources[n++] = lunasvg_sources[i];

        if (!nob_needs_rebuild(lib_path, all_sources, n)) {
            nob_log(NOB_INFO, "lunasvg is up to date");
            return true;
        }
    }

    if (!nob_mkdir_if_not_exists(obj_dir)) return false;

    // Compile plutovg C sources
    for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
        const char *src = plutovg_sources[i];
        // Extract filename for .o
        const char *base = strrchr(src, '/');
        base = base ? base + 1 : src;
        char obj_name[256];
        snprintf(obj_name, sizeof(obj_name), "%s", base);
        char *dot = strrchr(obj_name, '.');
        if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
        const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);

        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "clang");
        nob_cmd_append(&cmd, "-std=c11", "-c");
        nob_cmd_append(&cmd, "-DPLUTOVG_BUILD", "-DPLUTOVG_BUILD_STATIC");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/include");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/source");
        nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
        if (debug) {
            nob_cmd_append(&cmd, "-g", "-O0");
        } else {
            nob_cmd_append(&cmd, "-O2");
        }
        nob_cmd_append(&cmd, "-o", obj_path);
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Compile lunasvg C++ sources
    for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
        const char *src = lunasvg_sources[i];
        const char *base = strrchr(src, '/');
        base = base ? base + 1 : src;
        char obj_name[256];
        snprintf(obj_name, sizeof(obj_name), "%s", base);
        char *dot = strrchr(obj_name, '.');
        if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
        const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);

        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "clang++");
        nob_cmd_append(&cmd, "-std=c++17", "-c");
        nob_cmd_append(&cmd, "-fno-exceptions", "-fno-rtti");
        nob_cmd_append(&cmd, "-DLUNASVG_BUILD", "-DLUNASVG_BUILD_STATIC", "-DPLUTOVG_BUILD_STATIC");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/include");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/source");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/include");
        nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
        if (debug) {
            nob_cmd_append(&cmd, "-g", "-O0");
        } else {
            nob_cmd_append(&cmd, "-O2");
        }
        nob_cmd_append(&cmd, "-o", obj_path);
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Archive into static library
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "ar", "rcs", lib_path);
        for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
            const char *src = plutovg_sources[i];
            const char *base = strrchr(src, '/');
            base = base ? base + 1 : src;
            char obj_name[256];
            snprintf(obj_name, sizeof(obj_name), "%s", base);
            char *dot = strrchr(obj_name, '.');
            if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
            nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
        }
        for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
            const char *src = lunasvg_sources[i];
            const char *base = strrchr(src, '/');
            base = base ? base + 1 : src;
            char obj_name[256];
            snprintf(obj_name, sizeof(obj_name), "%s", base);
            char *dot = strrchr(obj_name, '.');
            if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
            nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
        }
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Clean up obj dir — only the .a is needed
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "rm", "-rf", obj_dir);
        Nob_Cmd_Opt copt = {0};
        nob_cmd_run_opt(&cmd, copt);
    }

    nob_log(NOB_INFO, "Built %s", lib_path);
    return true;
}

static bool build_freetype_lib(const char *build_dir, bool debug) {
    const char *obj_dir = nob_temp_sprintf("%s/freetype_obj", build_dir);
    const char *lib_path = "vendor/freetype/libfreetype.a";

    if (!nob_needs_rebuild(lib_path, freetype_sources, NOB_ARRAY_LEN(freetype_sources))) {
        nob_log(NOB_INFO, "freetype is up to date");
        return true;
    }

    if (!nob_mkdir_if_not_exists(obj_dir)) return false;

    for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
        const char *src = freetype_sources[i];
        const char *base = strrchr(src, '/');
        base = base ? base + 1 : src;
        char obj_name[256];
        snprintf(obj_name, sizeof(obj_name), "%s", base);
        char *dot = strrchr(obj_name, '.');
        if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
        const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);

        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "clang");
        nob_cmd_append(&cmd, "-std=c11", "-c");
        nob_cmd_append(&cmd, "-DFT2_BUILD_LIBRARY");
        nob_cmd_append(&cmd, "-Ivendor/freetype/include");
        nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
        if (debug) {
            nob_cmd_append(&cmd, "-g", "-O0");
        } else {
            nob_cmd_append(&cmd, "-O2");
        }
        nob_cmd_append(&cmd, "-o", obj_path);
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Archive
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "ar", "rcs", lib_path);
        for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
            const char *src = freetype_sources[i];
            const char *base = strrchr(src, '/');
            base = base ? base + 1 : src;
            char obj_name[256];
            snprintf(obj_name, sizeof(obj_name), "%s", base);
            char *dot = strrchr(obj_name, '.');
            if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
            nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
        }
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Clean up obj dir
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "rm", "-rf", obj_dir);
        Nob_Cmd_Opt copt = {0};
        nob_cmd_run_opt(&cmd, copt);
    }

    nob_log(NOB_INFO, "Built %s", lib_path);
    return true;
}

int main(int argc, char **argv) {
    NOB_GO_REBUILD_URSELF(argc, argv);

    bool debug = false;
    bool clean = false;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "debug") == 0) debug = true;
        else if (strcmp(argv[i], "clean") == 0) clean = true;
        else {
            nob_log(NOB_ERROR, "unknown argument: %s", argv[i]);
            nob_log(NOB_ERROR, "usage: %s [debug] [clean]", argv[0]);
            return 1;
        }
    }

    const char *build_dir = debug ? "build_debug" : "build_release";

    if (clean) {
        nob_log(NOB_INFO, "Cleaning build artifacts");
        { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "rm", "-rf", "build_debug");
          Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
        { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "rm", "-rf", "build_release");
          Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
        remove("vendor/lunasvg/liblunasvg.a");
        remove("vendor/freetype/libfreetype.a");
        remove("src/renderer/font_inter.gen.h");
        return 0;
    }

    // App bundle paths
    const char *app_dir     = nob_temp_sprintf("%s/autosample.app", build_dir);
    const char *contents    = nob_temp_sprintf("%s/Contents", app_dir);
    const char *macos_dir   = nob_temp_sprintf("%s/Contents/MacOS", app_dir);
    const char *res_dir     = nob_temp_sprintf("%s/Contents/Resources", app_dir);
    const char *binary_path = nob_temp_sprintf("%s/Contents/MacOS/autosample", app_dir);

    if (!nob_mkdir_if_not_exists(build_dir)) return 1;
    if (!nob_mkdir_if_not_exists(app_dir))   return 1;
    if (!nob_mkdir_if_not_exists(contents))  return 1;
    if (!nob_mkdir_if_not_exists(macos_dir)) return 1;
    if (!nob_mkdir_if_not_exists(res_dir))   return 1;

    // Build static libraries
    if (!build_lunasvg_lib(build_dir, debug)) return 1;
    if (!build_freetype_lib(build_dir, debug)) return 1;

    // Generate embedded font header
    if (!embed_font_file("assets/fonts/Inter-Regular.ttf",
                         "src/renderer/font_inter.gen.h")) return 1;

    // Unity build: single clang++ invocation compiles main.cpp (which #includes everything)
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "clang++");
        nob_cmd_append(&cmd, "-std=c++20", "-x", "objective-c++");
        nob_cmd_append(&cmd, "-fno-exceptions", "-fno-rtti");
        nob_cmd_append(&cmd, "-Wall", "-Wextra", "-Wno-missing-field-initializers");
        nob_cmd_append(&cmd, "-Wno-deprecated-declarations");
        nob_cmd_append(&cmd, "-Isrc", "-Ivendor/clay");
        nob_cmd_append(&cmd, "-Ivendor/lunasvg/include");
        nob_cmd_append(&cmd, "-Ivendor/freetype/include");
        nob_cmd_append(&cmd, "-DLUNASVG_BUILD_STATIC");

        if (debug) {
            nob_cmd_append(&cmd, "-g", "-O0", "-D_DEBUG");
        } else {
            nob_cmd_append(&cmd, "-O2", "-DNDEBUG");
        }

        nob_cmd_append(&cmd, "-o", binary_path);
        nob_cmd_append(&cmd, "src/main.cpp");

        // Reset language mode so .a is treated as a library, not source
        nob_cmd_append(&cmd, "-x", "none");
        nob_cmd_append(&cmd, "vendor/lunasvg/liblunasvg.a");
        nob_cmd_append(&cmd, "vendor/freetype/libfreetype.a");

        {
            size_t i;
            for (i = 0; i < NOB_ARRAY_LEN(frameworks); i++)
                nob_cmd_append(&cmd, frameworks[i]);
        }
        nob_cmd_append(&cmd, "-lstdc++");
        { Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
    }

    // Write Info.plist
    {
        const char *plist_path = nob_temp_sprintf("%s/Contents/Info.plist", app_dir);
        nob_write_entire_file(plist_path,
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\n"
            "  \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
            "<plist version=\"1.0\">\n"
            "<dict>\n"
            "  <key>CFBundleExecutable</key>\n"
            "  <string>autosample</string>\n"
            "  <key>CFBundleIdentifier</key>\n"
            "  <string>com.autosample.app</string>\n"
            "  <key>CFBundleName</key>\n"
            "  <string>autosample</string>\n"
            "  <key>CFBundleVersion</key>\n"
            "  <string>0.1</string>\n"
            "  <key>CFBundleShortVersionString</key>\n"
            "  <string>0.1</string>\n"
            "  <key>CFBundlePackageType</key>\n"
            "  <string>APPL</string>\n"
            "  <key>NSHighResolutionCapable</key>\n"
            "  <true/>\n"
            "  <key>NSSupportsAutomaticGraphicsSwitching</key>\n"
            "  <true/>\n"
            "</dict>\n"
            "</plist>\n",
            strlen(
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\n"
            "  \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
            "<plist version=\"1.0\">\n"
            "<dict>\n"
            "  <key>CFBundleExecutable</key>\n"
            "  <string>autosample</string>\n"
            "  <key>CFBundleIdentifier</key>\n"
            "  <string>com.autosample.app</string>\n"
            "  <key>CFBundleName</key>\n"
            "  <string>autosample</string>\n"
            "  <key>CFBundleVersion</key>\n"
            "  <string>0.1</string>\n"
            "  <key>CFBundleShortVersionString</key>\n"
            "  <string>0.1</string>\n"
            "  <key>CFBundlePackageType</key>\n"
            "  <string>APPL</string>\n"
            "  <key>NSHighResolutionCapable</key>\n"
            "  <true/>\n"
            "  <key>NSSupportsAutomaticGraphicsSwitching</key>\n"
            "  <true/>\n"
            "</dict>\n"
            "</plist>\n"
            ));
    }

    nob_log(NOB_INFO, "Build complete: %s", app_dir);
    return 0;
}

#else
////////////////////////////////
// Windows build (MSVC cl.exe)

static const char *link_libs[] = {
    "d3d12.lib",
    "dxgi.lib",
    "d3dcompiler.lib",
    "user32.lib",
    "gdi32.lib",
    "shell32.lib",
    "ole32.lib",
    "advapi32.lib",
    "dwmapi.lib",
    "winmm.lib",
};

static bool build_lunasvg_lib(const char *build_dir, bool debug) {
    const char *obj_dir = nob_temp_sprintf("%s\\lunasvg_obj", build_dir);
    const char *lib_path = debug ? "vendor\\lunasvg\\lunasvg_d.lib" : "vendor\\lunasvg\\lunasvg.lib";

    // Check if rebuild is needed
    {
        const char *all_sources[NOB_ARRAY_LEN(plutovg_sources) + NOB_ARRAY_LEN(lunasvg_sources)];
        size_t n = 0;
        for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++)
            all_sources[n++] = plutovg_sources[i];
        for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++)
            all_sources[n++] = lunasvg_sources[i];

        if (!nob_needs_rebuild(lib_path, all_sources, n)) {
            nob_log(NOB_INFO, "lunasvg is up to date");
            return true;
        }
    }

    if (!nob_mkdir_if_not_exists(obj_dir)) return false;

    // Compile plutovg C sources
    for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
        const char *src = plutovg_sources[i];
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
        nob_cmd_append(&cmd, "/std:c11");
        nob_cmd_append(&cmd, "/DPLUTOVG_BUILD", "/DPLUTOVG_BUILD_STATIC");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/include");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/source");
        nob_cmd_append(&cmd, "/W3");
        if (debug) {
            nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
        } else {
            nob_cmd_append(&cmd, "/MT", "/O2");
        }
        nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Compile lunasvg C++ sources
    for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
        const char *src = lunasvg_sources[i];
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
        nob_cmd_append(&cmd, "/std:c++17", "/EHsc");
        nob_cmd_append(&cmd, "/DLUNASVG_BUILD", "/DLUNASVG_BUILD_STATIC", "/DPLUTOVG_BUILD_STATIC");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/include");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/source");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/include");
        nob_cmd_append(&cmd, "/W3");
        if (debug) {
            nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
        } else {
            nob_cmd_append(&cmd, "/MT", "/O2");
        }
        nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Archive into static library
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "lib.exe", "/nologo", nob_temp_sprintf("/OUT:%s", lib_path));
        nob_cmd_append(&cmd, nob_temp_sprintf("%s/*.obj", obj_dir));
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Clean up obj dir — only the .lib is needed
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cmd.exe", "/c",
            nob_temp_sprintf("if exist %s rmdir /s /q %s", obj_dir, obj_dir));
        Nob_Cmd_Opt copt = {0};
        nob_cmd_run_opt(&cmd, copt);
    }

    nob_log(NOB_INFO, "Built %s", lib_path);
    return true;
}

static bool build_freetype_lib(const char *build_dir, bool debug) {
    const char *obj_dir = nob_temp_sprintf("%s\\freetype_obj", build_dir);
    const char *lib_path = debug ? "vendor\\freetype\\freetype_d.lib" : "vendor\\freetype\\freetype.lib";

    if (!nob_needs_rebuild(lib_path, freetype_sources, NOB_ARRAY_LEN(freetype_sources))) {
        nob_log(NOB_INFO, "freetype is up to date");
        return true;
    }

    if (!nob_mkdir_if_not_exists(obj_dir)) return false;

    for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
        const char *src = freetype_sources[i];
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
        nob_cmd_append(&cmd, "/std:c11");
        nob_cmd_append(&cmd, "/DFT2_BUILD_LIBRARY");
        nob_cmd_append(&cmd, "/Ivendor/freetype/include");
        nob_cmd_append(&cmd, "/W3");
        if (debug) {
            nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
        } else {
            nob_cmd_append(&cmd, "/MT", "/O2");
        }
        nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
        nob_cmd_append(&cmd, src);
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Archive
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "lib.exe", "/nologo", nob_temp_sprintf("/OUT:%s", lib_path));
        nob_cmd_append(&cmd, nob_temp_sprintf("%s/*.obj", obj_dir));
        Nob_Cmd_Opt copt = {0};
        if (!nob_cmd_run_opt(&cmd, copt)) return false;
    }

    // Clean up obj dir
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cmd.exe", "/c",
            nob_temp_sprintf("if exist %s rmdir /s /q %s", obj_dir, obj_dir));
        Nob_Cmd_Opt copt = {0};
        nob_cmd_run_opt(&cmd, copt);
    }

    nob_log(NOB_INFO, "Built %s", lib_path);
    return true;
}

int main(int argc, char **argv) {
    NOB_GO_REBUILD_URSELF(argc, argv);

    bool debug = false;
    bool clean = false;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "debug") == 0) debug = true;
        else if (strcmp(argv[i], "clean") == 0) clean = true;
        else {
            nob_log(NOB_ERROR, "unknown argument: %s", argv[i]);
            nob_log(NOB_ERROR, "usage: %s [debug] [clean]", argv[0]);
            return 1;
        }
    }

    const char *build_dir = debug ? "build_debug" : "build_release";

    if (clean) {
        nob_log(NOB_INFO, "Cleaning build artifacts");
        { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cmd.exe", "/c",
            "if exist build_debug rmdir /s /q build_debug");
          Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
        { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cmd.exe", "/c",
            "if exist build_release rmdir /s /q build_release");
          Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
        remove("vendor\\lunasvg\\lunasvg.lib");
        remove("vendor\\lunasvg\\lunasvg_d.lib");
        remove("vendor\\freetype\\freetype.lib");
        remove("vendor\\freetype\\freetype_d.lib");
        remove("src\\renderer\\font_inter.gen.h");
        return 0;
    }

    if (!nob_mkdir_if_not_exists(build_dir)) return 1;

    // Build static libraries
    if (!build_lunasvg_lib(build_dir, debug)) return 1;
    if (!build_freetype_lib(build_dir, debug)) return 1;

    // Generate embedded font header
    if (!embed_font_file("assets/fonts/Inter-Regular.ttf",
                         "src\\renderer\\font_inter.gen.h")) return 1;

    // Unity build: single cl.exe invocation compiles main.cpp (which #includes everything)
    {
        Nob_Cmd cmd = {0};
        nob_cmd_append(&cmd, "cl.exe");
        nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
        nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
        nob_cmd_append(&cmd, "/Ivendor/lunasvg/include");
        nob_cmd_append(&cmd, "/Ivendor/freetype/include");
        nob_cmd_append(&cmd, "/DLUNASVG_BUILD_STATIC");

        if (debug) {
            nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
        } else {
            nob_cmd_append(&cmd, "/MT", "/Zi", "/O2", "/DNDEBUG");
        }

        nob_cmd_append(&cmd, nob_temp_sprintf("/Fe:%s/autosample.exe", build_dir));
        nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", build_dir));
        nob_cmd_append(&cmd, nob_temp_sprintf("/Fd:%s/autosample.pdb", build_dir));

        nob_cmd_append(&cmd, "src/main.cpp");

        nob_cmd_append(&cmd, "/link");
        nob_cmd_append(&cmd, "/MACHINE:X64");
        nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
        nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", build_dir));
        nob_cmd_append(&cmd, "/DEBUG");
        nob_cmd_append(&cmd, debug ? "vendor/lunasvg/lunasvg_d.lib" : "vendor/lunasvg/lunasvg.lib");
        nob_cmd_append(&cmd, debug ? "vendor/freetype/freetype_d.lib" : "vendor/freetype/freetype.lib");
        {
            size_t i;
            for (i = 0; i < NOB_ARRAY_LEN(link_libs); i++)
                nob_cmd_append(&cmd, link_libs[i]);
        }
        { Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
    }

    // Clean up obj files
    nob_delete_file(nob_temp_sprintf("%s/main.obj", build_dir));

    nob_log(NOB_INFO, "Build complete: %s/autosample.exe", build_dir);
    return 0;
}

#endif
