from pprint import pprint as pp
import PySimpleGUI as sg
from shared import load_rows
from scanf import scanf
from string import ascii_letters
import re

WATCHERS = {}
OUTPUT = []


def load_crates(x):
    done_crates = False
    crates = []
    instructions = []
    for row in x:
        if done_crates:
            instructions.append(row)
        else:
            if row == "":
                done_crates = True
            else:
                crates.append(row)
    crates.pop()
    return crates, instructions


def to_lists(crates):
    parsed = []
    reg = re.compile(r"[\([{})\]]")
    for row in crates:
        parsed.append([x for x in reg.sub(" ", row)])
    parsed = list(zip(*parsed[::-1]))
    parsed = list(zip(*parsed[::-1]))
    parsed = list(zip(*parsed[::-1]))
    cleaned1 = [[x for x in y if x.strip()] for y in parsed if y]
    cleaned2 = [x for x in cleaned1 if x != []][::-1]
    return cleaned2


def parse_instructions(crates, instructions):
    for instruction in instructions:
        count, _from, _to = scanf("move %d from %d to %d", instruction)
        update_watchers("count", count)
        update_output(" ".join(map(str, (count, _from, _to))))
        _from -= 1  # 1 based yo
        _to -= 1
        for x in range(count):
            value = crates[_from].pop(0)
            crates[_to].insert(0, value)
    return crates


def parse_instructions_pt2(crates, instructions):
    for instruction in instructions:
        count, _from, _to = scanf("move %d from %d to %d", instruction)
        _from -= 1  # 1 based yo
        _to -= 1
        moving = crates[_from][:count]
        update_output(" ".join(map(str, (instruction, moving))))
        for x in range(count):
            crates[_from].pop(0)
        for x in reversed(moving):
            crates[_to].insert(0, x)

    return crates


def part1(x):
    crates, instructions = load_crates(x)
    crates = to_lists(crates)
    crates = parse_instructions(crates, instructions)
    update_output("".join([c[0] for c in crates]))


def part2(x):
    crates, instructions = load_crates(x)
    crates = parse_instructions_pt2(crates, instructions)
    update_output("".join([c[0] for c in crates]))


def main():
    rows = load_rows(5)
    sg_window(rows)


sg.Window("Day5")
sg.theme("DarkAmber")
watch_column = [
    [sg.Text("Watch Column")],
    [sg.Text("------------")],
    [sg.Text("", key="-WATCH-")],
]
output_column = [
    [sg.Text("Output Column")],
    [sg.Text("------------")],
    [sg.Text("", key="-OUTPUT-")],
]

layout = [
    [sg.Button("Part1"), sg.Button("Part2"), sg.Button("X")],
    [
        sg.Column(watch_column),
        sg.VSeperator(),
        sg.Column(output_column),
    ],
]

window = sg.Window("App", layout)


def update_output(new):
    new = new.split("\n")
    global OUTPUT
    OUTPUT.extend(new)
    if len(OUTPUT) > 40:
        OUTPUT = OUTPUT[len(new) :]
    window["-OUTPUT-"].update("\n".join(OUTPUT))


def watcher_to_string():
    s = ""
    for k, v in WATCHERS.items():
        s += f"{k}:{v}\n"
    return s


def update_watchers(k, v):
    WATCHERS[k] = v
    window["-WATCH-"].update(watcher_to_string())


def sg_window(rows):
    while True:
        event, values = window.Read()
        if event == "X" or event == sg.WIN_CLOSED:
            break
        if event == "Part1":
            part1(rows)
        if event == "Part2":
            part2(rows)

    window.Close()

    # part1(rows)
    # part2(rows)


if __name__ == "__main__":
    main()
