const std = @import("std");

const path = "data/day24/input.txt";

const input_counter = 14; // number of instruction blocks
const input_length = 18; // items in each instruction block
const offset0 = 5;
const offset1 = 15;

const PairType = i9;
const Pair = [2]PairType;
const Pairs = [input_counter]Pair;

pub fn main() !void {
    var buf: [100]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buf);

    var timer = try std.time.Timer.start();
    const ret = try second(fba.allocator());
    const t = timer.lap() / 1000;

    try std.testing.expectEqual(@as(usize, 93185111127911), ret);

    std.debug.print("Day 24b result: {d} \ttime: {d}us\n", .{ ret, t });
}

pub fn second(allocator: ?std.mem.Allocator) !usize {
    const start = 1;
    const pairs = try parseInput();

    var stack = std.ArrayList(Pair).init(allocator.?);
    defer stack.deinit();

    var ret: usize = 0;

    var i: usize = 0;
    while (i < input_counter) : (i += 1) {
        if (pairs[i][0] > 0) {
            try stack.append(Pair{ pairs[i][1], @intCast(PairType, i) });
        } else {
            const p = stack.pop();

            var add: PairType = start;
            while (add + p[0] + pairs[i][0] < start) {
                add += 1;
            }

            ret += @intCast(usize, add) *
                try std.math.powi(usize, 10, @intCast(usize, input_counter - 1 - p[1]));
            ret += @intCast(usize, (add + p[0] + pairs[i][0])) *
                try std.math.powi(usize, 10, input_counter - 1 - i);
        }
    }

    return ret;
}

fn parseInput() !Pairs {
    const input = @embedFile(path);
    var line = std.mem.split(u8, input, "\n");

    var ret: Pairs = undefined;

    var line_counter: usize = 0;
    var item_counter: usize = 0;
    while (line.next()) |l| : (line_counter += 1) {
        if (line_counter == input_length * item_counter + offset0) {
            var token = std.mem.tokenize(u8, l, " ");
            _ = token.next();
            _ = token.next();
            ret[item_counter][0] = try std.fmt.parseInt(PairType, token.next().?, 10);
        }

        if (line_counter == input_length * item_counter + offset1) {
            var token = std.mem.tokenize(u8, l, " ");
            _ = token.next();
            _ = token.next();
            ret[item_counter][1] = try std.fmt.parseInt(PairType, token.next().?, 10);
            item_counter += 1;
        }
    }

    return ret;
}

test "day24b" {
    try std.testing.expectEqual(@as(usize, 93185111127911), try second(std.testing.allocator));
}