const std = @import("std");

const Str = []const u8;

const DAYS = 18;

const aoc2015 = struct {
    const day01 = @import("day01.zig");
    const day02 = @import("day02.zig");
    const day03 = @import("day03.zig");
    const day04 = @import("day04.zig");
    const day05 = @import("day05.zig");
    const day06 = @import("day06.zig");
    const day07 = @import("day07.zig");
    const day08 = @import("day08.zig");
    const day09 = @import("day09.zig");
    const day10 = @import("day10.zig");
    const day11 = @import("day11.zig");
    const day12 = @import("day12.zig");
    const day13 = @import("day13.zig");
    const day14 = @import("day14.zig");
    const day15 = @import("day15.zig");
    const day16 = @import("day16.zig");
    const day17 = @import("day17.zig");
    const day18 = @import("day18.zig");
};

test {
    _ = @import("day01.zig");
    _ = @import("day02.zig");
    _ = @import("day03.zig");
    _ = @import("day04.zig");
    _ = @import("day05.zig");
    _ = @import("day06.zig");
    _ = @import("day07.zig");
    _ = @import("day08.zig");
    _ = @import("day09.zig");
    _ = @import("day10.zig");
    _ = @import("day11.zig");
    _ = @import("day12.zig");
    _ = @import("day13.zig");
    _ = @import("day14.zig");
    _ = @import("day15.zig");
    _ = @import("day16.zig");
    _ = @import("day17.zig");
    _ = @import("day18.zig");
}

pub fn main() anyerror!void {
    var timer = try std.time.Timer.start();
    var time_sum: usize = 0;

    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    var buffer = std.io.bufferedWriter(std.io.getStdOut().writer());
    const stdout = buffer.writer();

    try stdout.print("{s:<8}{s:>45}{s:>20}\n", .{ "Day", "Result", "Time" });

    comptime var day: u5 = 0;
    inline while (day < DAYS) : (day += 1) {
        comptime var buf: [5]u8 = undefined;
        const day_str = comptime try std.fmt.bufPrint(&buf, "day{d:0>2}", .{day + 1});

        timer.reset();
        const first_res = @field(aoc2015, day_str).first(arena.allocator()) catch unreachable;
        const first_time = timer.read() / std.time.ns_per_us;
        time_sum += first_time;

        if (@TypeOf(first_res) == Str) {
            try stdout.print("{s}a: {s:>45}{d:>20} us\n", .{ day_str, first_res, first_time });
        } else {
            try stdout.print("{s}a: {d:>45}{d:>20} us\n", .{ day_str, first_res, first_time });
        }

        if (day < 24) {
            timer.reset();
            const second_res = @field(aoc2015, day_str).second(arena.allocator()) catch unreachable;
            const second_time = timer.read() / std.time.ns_per_us;
            time_sum += second_time;

            if (@TypeOf(second_res) == Str) {
                try stdout.print("{s}b: {s:>45}{d:>20} us\n", .{ day_str, second_res, second_time });
            } else {
                try stdout.print("{s}b: {d:>45}{d:>20} us\n", .{ day_str, second_res, second_time });
            }
        }
    }

    try stdout.print("Total time: {d} ms\n", .{time_sum / std.time.us_per_ms});

    try buffer.flush();
}