import shared
from pprint import pprint
from dataclasses import dataclass


@dataclass
class Mapping:
    dst: int
    src: int
    ran: int  # RANGE


maps_parts = [
    "seed-to-soil",
    "soil-to-fertilizer",
    "fertilizer-to-water",
    "water-to-light",
    "light-to-temperature",
    "temperature-to-humidity",
    "humidity-to-location",
]

group = lambda l, s: list(zip(*(iter(l),) * s))


def line_ints(s):
    return [int(x) for x in s.split() if s]


def parse_line(line):
    return Mapping(*line)


class Mapper:
    def __init__(self, rows):
        self.parse(rows)

    def parse(self, rows):
        seeds = rows.pop(0)
        rows.pop(0)  # Discard empty to start at a clean slate
        seeds = line_ints(seeds.split(":")[1])
        maps = {}
        current_map = None
        for row in rows:
            if ":" in row:
                current_map = row[:-5]
                maps[current_map] = []
                continue
            if row == "":
                continue
            maps[current_map].append(parse_line(line_ints(row)))
        self.seeds = seeds
        self.maps = maps

    def calculate(self, step, source):
        possibilities = self.maps[step]
        for p in possibilities:
            if source < p.src:
                # print(f"\t{source} less than {p.src}")
                continue
            if source > p.src + p.ran:
                # print(f"\t{source} greater than {p.src}+{p.ran}={p.src+p.ran}")
                continue
            # print(f"\t{source} in range")
            # print(f"\t{source} is {p.dst + (source - p.src)}")
            return p.dst + (source - p.src)
            break
        return source


# @shared.profile
def part1(rows):
    mapper = Mapper(rows[:])
    locations = []

    for seed in mapper.seeds:
        next = seed
        for part in maps_parts:
            _part = next
            next = mapper.calculate(part, next)
        locations.append(next)
    print(locations)
    print(min(locations))


# @shared.profile
def part2(rows):
    mapper = Mapper(rows[:])
    locations = []
    seeds = group(mapper.seeds, 2)

    for seed_group in seeds:
        for seed in range(seed_group[0], seed_group[0] + seed_group[1]):
            next = seed
            for part in maps_parts:
                _part = next
                next = mapper.calculate(part, next)
            locations.append(next)
    print(min(locations))


def main():
    rows = [row for row in shared.load_rows(5)]
    with shared.elapsed_timer() as elapsed:
        part1(rows)
        print("🕒", elapsed())

    with shared.elapsed_timer() as elapsed:
        part2(rows)
        print("🕒", elapsed())


if __name__ == "__main__":
    main()
