// Majora's Screensaver (expects zig v0.15.x)
// @author: Abner Coimbre <abner@terminal.click>
// @description: Sample C app for Windows, Mac & Linux. Adapted from floooh's sokol examples.

// The goal is to demonstrate how to write a cross-platform native app/game in vanilla C, using only Zig to compile.

// Single-Header Libraries:
// - Sokol (https://github.com/floooh/sokol): Windowing, input, and/or graphics
// - STB (https://github.com/nothings/stb): Loading images/assets

// Instructions
// ---
// 1. Ensure Zig is on your PATH: download from https://ziglang.org/download
// 2. Navigate to this project's folder
// 3. Run the `zig build` command
// 4. For a macOS App Bundle try `zig build bundle` instead
// ---
// You may now run the executable under zig-out/

// The command `zig build` executes build() below. Learn more at https://zig.guide/

const std = @import("std");

pub fn build(b: *std.Build) void {
    // Initial exe
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "screensaver",
        .root_module = b.createModule(.{
            .optimize = optimize,
            .target = target,
        }),
    });

    // Compiler flags: update as needed
    const win_flags = &[_][]const u8{
        "-DSOKOL_D3D11",
        "-O0",
        "-ggdb3",
        "-std=c99",
        "-Werror", // Without this we can't emit warnings. This is a Zig bug: https://github.com/ziglang/zig/issues/15912
    };

    const macos_flags = &[_][]const u8{
        "-ObjC",
        "-DSOKOL_METAL",
        "-O0",
        "-ggdb3",
        "-std=c99",
        "-Werror",
    };

    const linux_flags = &[_][]const u8{
        "-DSOKOL_GLCORE33",
        "-O0",
        "-ggdb3",
        "-std=c99",
        "-Werror",
    };

    // Add include folder(s)
    exe.addIncludePath(b.path("inc"));
    exe.addIncludePath(b.path("data/shaders"));

    // Which OS are we in?
    const tag = target.result.os.tag;

    // Select appropriate compiler flags
    const target_flags = switch (tag) {
        .windows => win_flags,
        .macos => macos_flags,
        .linux => linux_flags,
        else => {
            std.debug.print("Error: Unsupported OS! Contact abner@terminal.click\n", .{});
            std.process.exit(1);
        },
    };

    // Add our source code
    exe.addCSourceFile(.{ .file = b.path("main.c"), .flags = target_flags });

    // Link against C's standard library
    exe.linkLibC();

    // Link against appropriate system libraries
    switch (tag) {
        .windows => {
            exe.linkSystemLibrary("kernel32");
            exe.linkSystemLibrary("gdi32");
            exe.linkSystemLibrary("d3d11");
        },

        .macos => {
            exe.linkFramework("MetalKit");
            exe.linkFramework("Metal");
            exe.linkFramework("Cocoa");
            exe.linkFramework("QuartzCore");
        },

        .linux => {
            exe.linkSystemLibrary("GL");
            exe.linkSystemLibrary("X11");
            exe.linkSystemLibrary("Xi");
            exe.linkSystemLibrary("Xcursor");
        },

        else => unreachable,
    }

    b.installArtifact(exe);

    //
    // macOS App Bundle - prepares one if user called `zig build bundle`
    //
    // ---
    if (tag == .macos) {
        const app_name = "Screensaver";
        const bundle_path = b.fmt("zig-out/{s}.app/Contents", .{app_name});

        const mkdir = b.addSystemCommand(&.{
            "mkdir",                            "-p",
            b.fmt("{s}/MacOS", .{bundle_path}),
        });

        const mkdir_res = b.addSystemCommand(&.{
            "mkdir",                                "-p",
            b.fmt("{s}/Resources", .{bundle_path}),
        });

        const copy_exe = b.addSystemCommand(&.{
            "cp",
            b.getInstallPath(.bin, "screensaver"),
            b.fmt("{s}/MacOS/screensaver", .{bundle_path}),
        });
        copy_exe.step.dependOn(&mkdir.step);
        copy_exe.step.dependOn(b.getInstallStep());

        const plist_content =
        \\<?xml version="1.0" encoding="UTF-8"?>
        \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
        \\<plist version="1.0">
        \\<dict>
        \\    <key>CFBundleExecutable</key>
        \\    <string>screensaver</string>
        \\    <key>CFBundleIdentifier</key>
        \\    <string>click.terminal.screensaver</string>
        \\    <key>CFBundleName</key>
        \\    <string>Screensaver</string>
        \\    <key>CFBundlePackageType</key>
        \\    <string>APPL</string>
        \\    <key>CFBundleVersion</key>
        \\    <string>1.0</string>
        \\</dict>
        \\</plist>
        ;

        const write_files = b.addWriteFiles();
        const plist_file = write_files.add("Info.plist", plist_content);
        const copy_plist = b.addInstallFile(plist_file, b.fmt("{s}.app/Contents/Info.plist", .{app_name}));

        const copy_data = b.addSystemCommand(&.{
            "cp", "-R",
            "data",
            b.fmt("{s}/Resources/", .{bundle_path}),
        });
        copy_data.step.dependOn(&mkdir_res.step);

        const bundle_step = b.step("bundle", "Create macOS app bundle");
        bundle_step.dependOn(&copy_exe.step);
        bundle_step.dependOn(&copy_plist.step);
        bundle_step.dependOn(&mkdir_res.step);
        bundle_step.dependOn(&copy_data.step);
        bundle_step.dependOn(&copy_plist.step);
    }
    // ---

    //
    // We're done! Complete Zig's build graph
    //
    //---
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
    //---
}
