import tty
import termios
import select
import queue
import threading
import sys

from .keyboard_abc import KeyboardABC


UNIX_KEYS = {
    '\x1b[A': 'ArrowUp',
    '\x1b[B': 'ArrowDown',
    '\x1b[C': 'ArrowRight',
    '\x1b[D': 'ArrowLeft',
    '\x1b[H': 'Home',
    '\x1b[F': 'End',
    '\x1b[5~': 'PageUp',
    '\x1b[6~': 'PageDown',
    '\x1b[3~': 'Delete',
    '\x1b[2~': 'Insert',
    '\x1bOP': 'F1',
    '\x1bOQ': 'F2',
    '\x1bOR': 'F3',
    '\x1bOS': 'F4',
    '\x1b[15~': 'F5',
    '\x1b[17~': 'F6',
    '\x1b[18~': 'F7',
    '\x1b[19~': 'F8',
    '\x1b[20~': 'F9',
    '\x1b[21~': 'F10',
    '\x1b[23~': 'F11',
    '\x1b[24~': 'F12',
}


class KeyboardUnix(KeyboardABC):
    def __init__(self):
        self.queue = queue.Queue()
        self.running = False
        self.thread = None
        self.buffer = ""
        self.fd = sys.stdin.fileno()
        self.old_settings = termios.tcgetattr(self.fd)

    def _listener(self):
        tty.setcbreak(self.fd)
        try:
            while self.running:
                dr, _, _ = select.select([sys.stdin], [], [], 0.01)
                if dr:
                    ch = sys.stdin.read(1)
                    self.buffer += ch
                    matched = False
                    for seq, name in UNIX_KEYS.items():
                        if self.buffer == seq:
                            self.queue.put(name)
                            self.buffer = ""
                            matched = True
                            break
                        elif seq.startswith(self.buffer):
                            matched = True
                            break
                    if not matched:
                        if len(self.buffer) == 1:
                            if self.buffer == '\x1b':
                                self.queue.put("Escape")
                            else:
                                self.queue.put(self.buffer)
                        self.buffer = ""
        finally:
            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

    def start(self):
        if self.running:
            return
        self.running = True
        self.thread = threading.Thread(target=self._listener, daemon=True)
        self.thread.start()

    def stop(self):
        self.running = False
        if self.thread:
            self.thread.join()
            self.thread = None

    def get_key(self):
        return self.queue.get()
