from collections import deque

def process_modules(filename, debug=False):
    """
    Reads the module configuration from a file, initializes the modules, and simulates the pulse propagation.
    Returns the product of total high and low pulses after 1000 button presses.
    """
    with open(filename) as f:
        lines = f.read().splitlines()

    modules = {}
    broadcaster = []
    for line in lines:
        left, right = line.split(" -> ")
        destinations = right.split(", ")
        if left == "broadcaster":
            broadcaster = destinations
            continue

        module_type = left[0]
        module_name = left[1:]
        modules[module_name] = [
            module_type,
            False if module_type == "%" else {},
            destinations,
        ]

    # Initialize conjunction modules with False for each input
    for name, (_, _, destinations) in modules.items():
        for destination in destinations:
            if destination in modules and modules[destination][0] == "&":
                modules[destination][1][name] = False

    low, high = 0, 0

    for iteration in range(1000):
        queue = deque([("broadcaster", target, False) for target in broadcaster])

        while queue:
            name, target, pulse = queue.popleft()

            if debug:
                print(f"Iteration {iteration}: Processing {target}, Pulse: {'High' if pulse else 'Low'}")

            if target not in modules:
                continue

            module = modules[target]

            if module[0] == "%":
                if pulse:
                    continue
                module[1] = not module[1]
                new_pulse = module[1]
            else:
                module[1][name] = pulse
                new_pulse = not all(module[1].values())

            for destination in module[2]:
                queue.append((target, destination, new_pulse))
                # Count pulses when they are sent
                if new_pulse:
                    high += 1
                else:
                    low += 1

            if debug:
                print(f"Iteration {iteration}: {target} -> {'High' if new_pulse else 'Low'} to {module[2]}")

    return low * high

def test():
    """
    Runs the process_modules function with the test input and checks if it meets the expected outcome.
    """
    expected_result = 11687500  # Replace with the expected result of the test input
    test_result = process_modules("../test.txt", debug=True)
    assert test_result == expected_result, f"Test failed: Expected {expected_result}, got {test_result}"
    print(f"Test passed with result: {test_result}")

def main():
    """
    Main function to run the test and then process the actual puzzle input.
    """
    try:
        print("Running test...")
        test()
        print("Test passed. Running main input...")
        result = process_modules("../input.txt")
        print(f"Puzzle result: {result}")
    except AssertionError as e:
        print(str(e))
        print("Stopping execution due to test failure.")
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    main()
