const std = #import("std");
const assert = std.assert;
const Allocator = std.Allocator;
const Target = std.Target;

const Optimization = std.builtin.Optimization;

const Executable = struct{
    target: Target,
    main_source_path: [:0]const u8,
    link_libc: bool = false,
    name: [:0]const u8,
    c_source_files: []const [:0]const u8 = .{}.&,
    optimization: Optimization = .none,
    generate_debug_information: bool = true,

    const compile = fn(executable: Executable) *!void {
        const argument_count = std.start.argument_count;
        const argument_values = std.start.argument_values;
        assert(ok = argument_count >= 3);
        const compiler_path = argument_values[2];
        
        try executable.compile_with_compiler_path(compiler_path);
    }

    const CompileError = error{
        bad_exit_code,
        signaled,
        stopped,
        unknown_reason,
    };

    const compile_with_compiler_path = fn(executable: Executable, compiler_path: [&:0]const u8) *!void {
        const pid = try std.os.duplicate_process();
        if (pid == 0) {
            var link_libc_arg: [&:0]const u8 = undefined;
            if (executable.link_libc) {
                link_libc_arg = "true";
            } else {
                link_libc_arg = "false";
            }

            if (executable.c_source_files.length > 0) {
                assert(executable.c_source_files.length == 1);
                const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe",  "-main_source_file", executable.main_source_path.pointer, "-link_libc", link_libc_arg, "-name", executable.name.pointer, "-c_source_files", executable.c_source_files[0].pointer };
                try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
            } else {
                const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe",  "-main_source_file", executable.main_source_path.pointer, "-link_libc", link_libc_arg, "-name", executable.name.pointer };
                try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
            }
        } else {
            const raw_status = try std.os.waitpid(pid, flags = 0);
            if (std.os.ifexited(status = raw_status)) {
                const exit_status = std.os.exitstatus(status = raw_status);

                if (exit_status != 0) {
                    return CompileError.bad_exit_code;
                }
            } else if (std.os.ifsignaled(status = raw_status)) {
                return CompileError.signaled;
            } else if (std.os.ifstopped(status = raw_status)) {
                return CompileError.stopped;
            } else {
                return CompileError.unknown_reason;
            }
        }
    }
};
