const std = @import("std");

pub fn define_direction(num1: i32, num2: i32) i8 {
    if (num1 > num2) {
        return -1;
    } else if (num2 > num1) {
        return 1;
    } else {
        return 0;
    }
}

pub fn part_1() !void {
    var file = try std.fs.cwd().openFile("input.txt", .{});
    defer file.close();

    var buf_reader = std.io.bufferedReader(file.reader());
    var in_stream = buf_reader.reader();

    var safe_reports: u32 = 0;

    var buf: [2048]u8 = undefined;
    while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| {
        var is_safe = true;
        var first_round = true;
        var last_num: i32 = 0;
        var defined_direction = false;
        var direction: i8 = 0;
        var tokAny = std.mem.tokenizeAny(u8, line, " ");
        while (tokAny.next()) |num| {
            const n = try std.fmt.parseInt(i32, num, 10);
            if (first_round) {
                last_num = n;
                first_round = false;
                continue;
            }
            if (@abs(last_num - n) > 3) {
                is_safe = false;
                break;
            }

            const current_direction = define_direction(last_num, n);

            if (!defined_direction) {
                direction = current_direction;
                defined_direction = true;
            }
            if (current_direction != direction or current_direction == 0) {
                is_safe = false;
                break;
            }
            last_num = n;
        }

        if (is_safe) {
            safe_reports += 1;
        }
    }
    std.debug.print("Part 1: {}\n", .{safe_reports});
}

pub fn part_2() !void {
    var file = try std.fs.cwd().openFile("input.txt", .{});
    defer file.close();

    var buf_reader = std.io.bufferedReader(file.reader());
    var in_stream = buf_reader.reader();

    var safe_reports: u32 = 0;

    var buf: [2048]u8 = undefined;
    while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| {
        var is_safe = true;
        var round: i32 = -1;
        var last_num: i32 = 0;
        var defined_direction = false;
        var direction: i8 = 0;
        var shield = true; // very bad name lol
        var tokAny = std.mem.tokenizeAny(u8, line, " ");
        while (tokAny.next()) |num| {
            round += 1;
            const n = try std.fmt.parseInt(i32, num, 10);
            if (round == 0) {
                defined_direction = false;
                last_num = n;
                continue;
            }
            if (@abs(last_num - n) > 3) {
                if (shield) {
                    if (round == 1) {
                        defined_direction = false;
                        last_num = n;
                    }
                    shield = false;
                    continue;
                }
                is_safe = false;
                break;
            }

            const current_direction = define_direction(last_num, n);

            if (!defined_direction) {
                direction = current_direction;
                if (current_direction != 0) {
                    defined_direction = true;
                }
            }
            if (current_direction != direction or current_direction == 0) {
                if (shield) {
                    if (round == 2) {
                        defined_direction = false;
                        last_num = n;
                    }
                    shield = false;
                    continue;
                }
                is_safe = false;
                break;
            }
            last_num = n;
        }

        if (is_safe) {
            safe_reports += 1;
        }
    }
    std.debug.print("Part 2: {}\n", .{safe_reports});
}

pub fn main() !void {
    try part_1();
    try part_2();
}