import sys
from dataclasses import dataclass, field

DEBUG = False
debug_padding = 40

def debug_print(printname, *args):
    if DEBUG:
        print(f"{'DEBUG::'+printname:<{debug_padding}}", *args)



engine = [];
parts = [];
part_numbers = [];



print("Parsing Input:")
print("")
print("===================================\n");


FILENAME = "/home/icaema/Public/advent-of-code/day-03/data/p02data.txt"
f = open(FILENAME, "r")
#for line in sys.stdin:
for line in f.readlines():
    line = line.strip()
    engine.append(line)
    #debug_print("input",  line)

# [https://stackoverflow.com/questions/17870612/printing-a-two-dimensional-array-in-python]
debug_print("engine")
print('\n'.join([''.join(['{:1}'.format(item) for item in row]) for row in engine]))




print("")
print(" Proccessing:")
print("===================================\n");


#=====Extract Parts=====

@dataclass
class Part:
    x: int = 0
    y: int = 0
    symbol: str = ''
    attached_numbers: set = field(default_factory=set)

def extractParts(engine, parts):
    for y in range(len(engine)):
        for x in range(len(engine[y])):
            #debug_print("slot ",f"x:{x}, y:{y}", engine[y][x])
            if engine[y][x] == '.' or engine[y][x].isdigit():
                continue
            parts.append(Part(x, y, engine[y][x]))
            #debug_print("Found Part", f"{parts[-1]}")

print("Extract Parts")
extractParts(engine, parts)
print(f"Found {len(parts)} parts")
#==============================


#=====Extract Part Numbers=====
@dataclass
class PartNumber:
    ascii: str = ""
    locations: list = field(default_factory=list)
    is_part_of_part = False
    def number(self):
        return int(self.ascii)

def extractPartNumbers(engine, part_numbers):
    current_parsing_part_number = PartNumber()
    for y in range(len(engine)):
        for x in range(len(engine[y])):
            if engine[y][x].isdigit():
                current_parsing_part_number.ascii += engine[y][x]
                current_parsing_part_number.locations.append([x,y])
            else:
                if current_parsing_part_number.ascii == "":
                    continue
                #debug_print("PARTNOEXT", f"found complete part number: {current_parsing_part_number['ascii'].rjust(4)}, locations: {current_parsing_part_number['locations']}")
                part_numbers.append(current_parsing_part_number)
                current_parsing_part_number = PartNumber()

print("Extract Part Numbers")
extractPartNumbers(engine, part_numbers)
print(f"Found {len(part_numbers)} part numbers")

#==============================


#=====Link Part Numbers to Parts=====

def linkPartNumbersToParts(part_numbers, parts):
    window = [
        [-1,-1],[0,-1],[1,-1],
        [-1, 0],[0, 0],[1, 0],
        [-1, 1],[0, 1],[1, 1]]
    for part_number in part_numbers:
        search_range = [[(digit[0] + t[0]), (digit[1] + t[1])] for t in window for digit in part_number.locations]
        for part in parts:
            if [part.x, part.y] in search_range:
                part_number.is_part_of_part= True
                part.attached_numbers.add(part_number.number())

print("Linking part numbers to parts")
linkPartNumbersToParts(part_numbers, parts)
#print(f"Linked {len(list(filter(lambda x: x.is_part_of_part == True, part_numbers)))} part numbers to {len(list(filter(lambda x: len(x.attached_numbers) != 0, parts)))} parts")

#==============================


if DEBUG:
    for part_number in part_numbers:
        debug_print("part_number print", part_number)
    for part in parts:
        debug_print("parts print", part)


print("")
print(" Calculate Answer:")
print("===================================\n");


part_numbers_that_are_attached_to_parts = [part_number.number() for part_number in part_numbers if part_number.is_part_of_part == True]
print(f"Found {len(part_numbers_that_are_attached_to_parts)} part numbers that are attached to a part")

gears = [part.attached_numbers for part in parts if part.symbol == '*' and len(part.attached_numbers) == 2]
print(f"Found {len(gears)} gears")
gear_ratios = [pn.pop()*pn.pop() for pn in gears]


print("")
print(" Answer:")
print("===================================\n");
print("sum of part numbers that are attached to parts:")
print(sum(part_numbers_that_are_attached_to_parts));
print("sum of gear ratios:")
print(sum(gear_ratios));