const std = @import("std");

fn day7_part1() !void {
    var inputs = try std.fs.cwd().openFile("inputs/day7.txt", .{});
    defer inputs.close();
    var buffered_reader = std.io.bufferedReader(inputs.reader());
    var in_stream = buffered_reader.reader();

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

    var buffer: [1024]u8 = undefined;

    var hands = std.ArrayList(Hand).init(allocator);
    while (try in_stream.readUntilDelimiterOrEof(&buffer, '\n')) |line| {
        var splitter = std.mem.splitScalar(u8, line, ' ');
        var card_section = splitter.next().?;
        var cards: []u8 = try allocator.alloc(u8, 5);
        std.mem.copy(u8, cards, card_section);
        var bid = try std.fmt.parseInt(u64, splitter.next().?, 10);

        std.log.info("{s}", .{cards});

        try hands.append(.{
            .bid = bid,
            .score = calc_score(cards),
            .score2 = calc_score2(cards),
            .cards = cards,
        });
    }

    std.mem.sort(Hand, hands.items, {}, hand_cmp);

    var result: u64 = 0;
    for (hands.items, 1..) |hand, i| {
        std.log.info("{s}, {d}, {d}, {d}", .{ hand.cards, hand.bid, hand.score, hand.score2 });
        result = i * hand.bid + result;
    }

    std.mem.sort(Hand, hands.items, {}, hand_cmp2);
    var result2: u64 = 0;
    for (hands.items, 1..) |hand, i| {
        std.log.info("{s}, {d}, {d}, {d}", .{ hand.cards, hand.bid, hand.score, hand.score2 });
        result2 = i * hand.bid + result2;
    }

    std.log.info("Result: {d}, {d}", .{ result, result2 });
}

const Hand = struct {
    bid: u64,
    score: u64,
    score2: u64,
    cards: []u8,
};

fn calc_score2(cards: []u8) u32 {
    var index = "J23456789TQKA";
    var count = std.mem.zeroes([index.len]u8);

    for (cards) |c| {
        var i = std.mem.indexOfScalar(u8, index, c).?;
        count[i] += 1;
    }

    var num_j = count[0];
    count[0] = 0;

    std.mem.sort(u8, &count, {}, std.sort.desc(u8));

    count[0] += num_j;

    var c: u32 = switch (count[0]) {
        5 => 10_000,
        4 => 9_000,
        3 => blk: {
            if (count[1] == 2) {
                break :blk 8_000;
            } else {
                break :blk 7_000;
            }
        },
        2 => blk: {
            if (count[1] == 2) {
                break :blk 6_000;
            } else {
                break :blk 5_000;
            }
        },
        else => 0,
    };

    return c;
}

fn calc_score(cards: []u8) u32 {
    var index = "23456789TJQKA";
    var count = std.mem.zeroes([index.len]u8);

    for (cards) |c| {
        var i = std.mem.indexOfScalar(u8, index, c).?;
        count[i] += 1;
    }

    std.mem.sort(u8, &count, {}, std.sort.desc(u8));

    var c: u32 = switch (count[0]) {
        5 => 10,
        4 => 9,
        3 => blk: {
            if (count[1] == 2) {
                break :blk 8;
            } else {
                break :blk 7;
            }
            break :blk 0;
        },
        2 => blk: {
            if (count[1] == 2) {
                break :blk 6;
            } else {
                break :blk 5;
            }
        },
        else => 0,
    };

    return c;
}

fn hand_cmp2(context: void, a: Hand, b: Hand) bool {
    _ = context;

    var index = "J23456789TQKA";
    if (a.score2 == b.score2) {
        for (0..a.cards.len) |i| {
            if (a.cards[i] == b.cards[i]) continue;

            return std.mem.indexOfScalar(u8, index, a.cards[i]).? < std.mem.indexOfScalar(u8, index, b.cards[i]).?;
        }
    }

    return a.score2 < b.score2;
}

fn hand_cmp(context: void, a: Hand, b: Hand) bool {
    _ = context;

    var index = "23456789TJQKA";
    if (a.score == b.score) {
        for (0..a.cards.len) |i| {
            if (a.cards[i] == b.cards[i]) continue;

            return std.mem.indexOfScalar(u8, index, a.cards[i]).? < std.mem.indexOfScalar(u8, index, b.cards[i]).?;
        }
    }

    return a.score < b.score;
}