#!/usr/bin/env python3
import os
import time
from collections import deque
from itertools import count
from Xlib import error
from detection import NOBLOCK
from interaction import get_exapunks_window, focus_window, screenshot_board, \
                        press_keys, listen_keys
from strategy import State


MAX_SPEED_ROWS = 3
MAX_LOOP = 6


def save_screenshot(win):
    board = screenshot_board(win).convert('RGB')
    os.makedirs('screens', exist_ok=True)
    for i in count(1):
        path = 'screens/board%d.png' % i
        if not os.path.exists(path):
            print('save screenshot in', path)
            board.save(path)
            break


if __name__ == '__main__':
    import sys
    verbose = '-q' not in sys.argv[1:]

    try:
        win = get_exapunks_window()
        focus_window(win)

        listen_keys({'s': lambda: save_screenshot(win)})

        buf = deque([], maxlen=MAX_LOOP)

        def vprint(*args, **kwargs):
            if verbose:
                print(*args, **kwargs)

        def vprint_state(state):
            if verbose:
                state.print()

        while True:
            try:
                board = screenshot_board(win)

                start = time.time()
                state = State.detect(board)
                end = time.time()
                vprint('\033c', end='')
                vprint('parsed in', round((end - start) * 1000, 1), 'ms:')
                vprint_state(state)
                vprint()

                if state.exa is None:
                    raise AssertionError

            except (TypeError, AssertionError):
                vprint('\rerror during parsing, wait for a bit...', end='')
                time.sleep(0.050)
                continue
            except error.BadMatch:
                vprint('\rEXAPUNKS window lost, wait for a bit...', end='')
                time.sleep(0.500)
                continue

            try:
                start = time.time()
                newstate = state.solve()
                end = time.time()
                vprint('thought for', round((end - start) * 1000, 1), 'ms')
            except AssertionError:
                print('error board 99:')
                state.print()
                board.convert('RGB').save('screens/board99.png')
                break

            if state.held == NOBLOCK and any(map(newstate.loops, buf)):
                vprint('\rloop detected, wait for a bit...', end='')
                time.sleep(0.030)
            elif newstate.moves:
                vprint('moves:', newstate.keys())
                vprint('score:', newstate.score)
                vprint()

                vprint('target after moves:')
                vprint_state(newstate)

                press_keys(win, newstate.keys())

                #keys_delay = len(newstate.moves) * 2 * KEY_DELAY
                #moves_delay = max(0, newstate.delay() - keys_delay)
                #vprint('wait for',  moves_delay, 'ms')
                #time.sleep(moves_delay / 1000)
                time.sleep(0.080)
            elif state.nrows - 2 <= MAX_SPEED_ROWS:
                vprint('no moves, speed up')
                press_keys(win, 'l')
                time.sleep(0.030)
            else:
                vprint('no moves')

            buf.append(newstate)
    except KeyboardInterrupt:
        print('interrupted, quitting')
