#import "File";
#import "String";
#import "Basic";
#import "Math";

solve_day5 :: (test: bool) {
    contents := read_entire_file("inputs/day5.txt");
    sections := split(contents, "\n\n");

    seeds_split := split(slice(sections[0], 7, sections[0].count - 7), " ");

    seeds: [..]u64;
    list_of_translations: [..][..]Seed_Translation;

    for seeds_split {
        array_add(*seeds, string_to_int(it, 10, u64));
    }

    for section: sections {
        lines := split(section, "\n");

        translation := array_add(*list_of_translations);

        for line: array_view(lines, 1, lines.count - 1) {
            if line.count == 0  continue;
            seeds := split(line, " ");

            source      := string_to_int(seeds[1], 10, u64);
            destination := string_to_int(seeds[0], 10, u64);
            amount      := string_to_int(seeds[2], 10, u64);

            array_add(translation, .{
                source      = source,
                destination = destination,
                amount      = amount,
            });
        }
    }

    smallest_val: u64 = U64_MAX;

    for seed: seeds {
        current_seed := seed;
        for list_of_translations {
            current_seed = convert_seed(current_seed, it);
        }

        smallest_val = min(smallest_val, current_seed);
    }

    print("Part 1: %\n", smallest_val);

    part2: u64 = U64_MAX;

    seed_ranges: [..]Seed_Range;

    for i: 0..(seeds.count - 1) / 2 {
        array_add(*seed_ranges, .{ from = seeds[i * 2], amount = seeds[i * 2 + 1] });
    }

    for seed_range: seed_ranges {
        work: [..]Seed_Range;
        array_add(*work, seed_range);

        for translations: list_of_translations {
            work = make_ranges(work, translations);

        }

        for item: work {
            part2 = min(part2, item.from);
        }
    }

    print("Part 2: %\n", part2);
}

make_ranges :: (seed_ranges: [..]Seed_Range, remap_ranges: [..]Seed_Translation) -> [..]Seed_Range {
    list1 := array_copy(seed_ranges);
    defer array_free(list1);
    list2: [..]Seed_Range;

    for remap_range: remap_ranges {
        for i: 0..list1.count - 1 {
            from   := list1[i].from;
            amount := list1[i].amount;
            to     := from + amount;

            if from >= remap_range.source && from < (remap_range.source + remap_range.amount) && 
               to > remap_range.source    && to  <= (remap_range.source + remap_range.amount) {
                array_add(*list2, .{
                    from = from + remap_range.destination - remap_range.source,
                    amount = amount,
                });

                list1[i].amount = 0;
                list1[i].from = U64_MAX;
            } else if from >= remap_range.source && from < (remap_range.source + remap_range.amount) {
                overlap := remap_range.source + remap_range.amount - from;

                list1[i].amount = amount - overlap;
                list1[i].from   = from + overlap;

                array_add(*list2, .{
                    from = remap_range.destination + (from - remap_range.source),
                    amount = overlap,
                });
            } else if to >= remap_range.source && to <= (remap_range.source + remap_range.amount) {
                overlap := from + amount - remap_range.source;
                list1[i].amount = amount - overlap;

                array_add(*list2, .{
                    from   = remap_range.destination,
                    amount = overlap,
                });
            }
        }
    }

    for item: list1 {
        if item.amount > 0 {
            array_add(*list2, item);
        }
    }

    return list2;

}

convert_seed :: (seed: u64, translations: [..]Seed_Translation) -> u64 {
    result := seed;
    for translation: translations {
        if translation.source <= result && (translation.source + translation.amount) > result {
            result = result + translation.destination - translation.source;
            break;
        }
    }
    return result;
}

Seed_Range :: struct {
    from:   u64;
    amount: u64;
}

Seed_Translation :: struct {
    source:      u64;
    destination: u64;
    amount:      u64;
}