const std = @import("std");
const allocator = std.heap.page_allocator;
const srcdir: []const u8 = "src";
const incdir: []const u8 = "include";
const cflags_default: []const []const u8 = &[_][]const u8{
    "-std=c2y",
    "-Wall",
    "-Wextra",
    "-Werror",
    "-Wimplicit-fallthrough",
    "-Wbitwise-instead-of-logical",
    "-Wconversion",
    "-Wdangling",
    "-Wdeprecated",
    "-Wdocumentation",
    "-Wmicrosoft",
    "-Wswitch-enum",
    "-Wswitch-default",
    "-Wtype-limits",
    "-Wunreachable-code-aggressive",
    "-Wpedantic",
    "-Wdocumentation-pedantic",
    "-Wno-dollar-in-identifier-extension",
    "-Wno-gnu",
};

pub fn build(b: *std.Build) !void {
    const a = std.heap.page_allocator;
    var cflags = try std.ArrayList([]const u8).initCapacity(a, 16);
    defer cflags.deinit(a);
    cflags.appendSlice(a, cflags_default) catch unreachable;

    const targ = b.standardTargetOptions(.{});
    const opti = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "rpx",
        .root_module = b.createModule(.{
            .optimize = opti,
            .target = targ,
            .link_libc = true,
        }),
    });

    exe.root_module.addIncludePath(b.path(incdir));

    const build_type: []const u8 =
        b.option([]const u8, "T", "Short form of TYPE") orelse
        b.option([]const u8, "TYPE", "Build type") orelse "";

    if (std.mem.eql(u8, build_type, "test")) {
        exe.root_module.addCMacro("TEST_MODE", "");
    } else if (std.mem.eql(u8, build_type, "bench")) {
        exe.root_module.addCMacro("BENCHMARK_MODE", "");
    }
    if (b.option([]const u8, "TEST_FILTER", "Test filter")) |filter| {
        exe.root_module.addCMacro("TEST_FILTER", filter);
    }

    addCSourcesFromDir(b, exe, srcdir, cflags.items);

    b.installArtifact(exe);

    const run_exe = b.addRunArtifact(exe);
    const run_step = b.step("run", "Run the code");
    run_step.dependOn(&run_exe.step);
}

/// not recursive
fn addCSourcesFromDir(b: *std.Build, exe: *std.Build.Step.Compile, dir: []const u8, cflags: []const []const u8) void {
    const io = b.graph.io;
    var diren = std.Io.Dir.cwd().openDir(io, dir, .{ .iterate = true }) catch unreachable;
    defer diren.close(io);
    var srcs = diren.iterate();
    while (srcs.next(io) catch unreachable) |src|
        if (std.mem.eql(u8, std.fs.path.extension(src.name), ".c"))
            exe.root_module.addCSourceFile(.{
                .file = b.path(b.fmt("{s}/{s}", .{ dir, src.name })),
                .flags = cflags,
                .language = .c,
            });
}