import itertools
from typing import List, TextIO, Tuple

from aoc2019.intcode import read_program, Computer


def amplify(phases: Tuple[int, ...], program: List[int]) -> int:
    amps: List[Computer] = []

    for i, phase in enumerate(phases):
        amp = Computer(program.copy())

        if i > 0:
            amp.input = amps[i - 1].output

        amp.input.append(phase)

        amps.append(amp)

    amps[0].input.append(0)

    for amp in amps:
        amp.run()

    return amps[-1].output.pop()


def reamplify(phases: Tuple[int, ...], program: List[int]) -> int:
    amps: List[Computer] = []

    for i, _ in enumerate(phases):
        amp = Computer(program.copy())

        if i > 0:
            amp.input = amps[i - 1].output

        amps.append(amp)

    amps[0].input = amps[-1].output

    for amp, phase in zip(amps, phases):
        amp.input.append(phase)

    amps[0].input.append(0)

    changes = True

    while changes:
        changes = False
        for amp in amps:
            try:
                amp.run()
            except IndexError:
                # Waiting for input
                changes = True

    return amps[-1].output.pop()


def part1(data: TextIO) -> int:
    program = read_program(data)

    return max(amplify(phase, program) for phase in itertools.permutations(range(0, 5)))


def part2(data: TextIO) -> int:
    program = read_program(data)

    return max(reamplify(phase, program) for phase in itertools.permutations(range(5, 10)))
