const std = @import("std");

const ArrayList = std.ArrayList;

const Vec2 = struct {
    x: i64 = 0,
    y: i64 = 0,
};

const LineSegment = struct {
    head: Vec2,
    tail: Vec2,
};

pub fn solve_part1(allocator: std.mem.Allocator, file: []const u8) !void {
    var inputs = try std.fs.cwd().openFile(file, .{});
    var buffered_reader = std.io.bufferedReader(inputs.reader());
    var in_stream = buffered_reader.reader();

    var buffer: [1024]u8 = undefined;

    var position: Vec2 = .{};
    var position_2: Vec2 = .{};

    var polygon = ArrayList(Vec2).init(allocator);
    var polygon_2 = ArrayList(Vec2).init(allocator);

    var perimeter: u32 = 0;
    var perimeter_2: u32 = 0;

    while (try in_stream.readUntilDelimiterOrEof(&buffer, '\n')) |line| {
        var index_after_amount = std.mem.indexOfScalar(u8, line[2..], ' ').?;
        var index_of_hashtag = std.mem.indexOfScalar(u8, line, '#').?;
        var amount = try std.fmt.parseInt(i32, line[2 .. index_after_amount + 2], 10);
        var amount_2 = try std.fmt.parseInt(i32, line[index_of_hashtag + 1 .. index_of_hashtag + 6], 16);
        perimeter += @intCast(amount);
        perimeter_2 += @intCast(amount_2);

        var dir = convert_to_vec2(line[0]);

        var dir_convert = [_]u8{ 'R', 'D', 'L', 'U' };
        var dir_2 = convert_to_vec2(dir_convert[line[index_of_hashtag + 6] - '0']);

        position.x += dir.x * amount;
        position.y += dir.y * amount;

        position_2.x += dir_2.x * amount_2;
        position_2.y += dir_2.y * amount_2;

        try polygon.append(position);
        try polygon_2.append(position_2);
    }

    std.log.info("Area: {d}", .{shoelace_area(polygon.items)});
    std.log.info("Area: {d}", .{perimeter});

    std.log.info("Part 1: {d}", .{shoelace_area(polygon.items) + perimeter / 2 + 1});
    std.log.info("Part 2: {d}", .{shoelace_area(polygon_2.items) + perimeter_2 / 2 + 1});
}

fn convert_to_vec2(dir: u8) Vec2 {
    switch (dir) {
        'U' => return .{ .x = 0, .y = 1 },
        'D' => return .{ .x = 0, .y = -1 },
        'L' => return .{ .x = -1, .y = 0 },
        'R' => return .{ .x = 1, .y = 0 },
        else => return .{ .x = 0, .y = 0 },
    }
}

fn shoelace_area(polygon: []Vec2) u64 {
    var area: i64 = 0;

    for (0..polygon.len) |i| {
        var p1 = polygon[i];
        var p2 = polygon[(i + 1) % polygon.len];

        area += p1.x * p2.y - p2.x * p1.y;
    }

    return @as(u64, @intCast(std.math.absInt(area) catch unreachable)) / 2;
}