import logging
import queue
import threading
from pathlib import Path

from . import zaudio, zfilesystem, zscreen, zstream, zui

logger = logging.getLogger(__name__)


class NullAudio(zaudio.ZAudio):
    def __init__(self):
        super().__init__()
        self.features = {"has_more_than_a_bleep": False}

    def play_bleep(self, bleep_type):
        pass


class MudScreen(zscreen.ZScreen):
    def __init__(self):
        super().__init__()
        self._buffer = []
        self._active_window = 0  # 0=lower (main text), 1=upper (status line)
        self._columns = 80
        self._rows = zscreen.INFINITE_ROWS
        self.features = {
            "has_status_line": False,
            "has_upper_window": False,
            "has_graphics_font": False,
            "has_text_colors": False,
        }

    def write(self, string):
        if self._active_window == 0:
            self._buffer.append(string)

    def flush(self) -> str:
        result = "".join(self._buffer)
        self._buffer.clear()
        return result

    def split_window(self, height):
        logger.debug(f"split_window({height})")

    def select_window(self, window):
        self._active_window = window

    def set_cursor_position(self, x, y):
        logger.debug(f"set_cursor_position({x}, {y}) - no-op")

    def erase_window(self, window=zscreen.WINDOW_LOWER, color=zscreen.COLOR_CURRENT):
        logger.debug(f"erase_window({window}, {color}) - no-op")

    def erase_line(self):
        logger.debug("erase_line() - no-op")

    def print_status_score_turns(self, text, score, turns):
        pass

    def print_status_time(self, hours, minutes):
        pass

    def set_font(self, font_number):
        if font_number == zscreen.FONT_NORMAL:
            return font_number
        return None

    def set_text_style(self, style):
        pass

    def set_text_color(self, foreground_color, background_color):
        pass


class MudInputStream(zstream.ZInputStream):
    def __init__(self):
        super().__init__()
        self._input_queue = queue.Queue()
        self._waiting = threading.Event()
        self._ready = threading.Event()
        self._done = False
        self.features = {"has_timed_input": False}

    def read_line(
        self,
        original_text=None,
        max_length=0,
        terminating_characters=None,
        timed_input_routine=None,
        timed_input_interval=0,
    ):
        self._waiting.set()
        self._ready.wait()
        self._ready.clear()
        self._waiting.clear()
        text = self._input_queue.get()
        if max_length > 0:
            text = text[:max_length]
        return text

    def read_char(self, timed_input_routine=None, timed_input_interval=0):
        self._waiting.set()
        self._ready.wait()
        self._ready.clear()
        self._waiting.clear()
        text = self._input_queue.get()
        if text:
            return ord(text[0])
        # Player hit Enter with no text — return 13 (ZSCII Enter/Return)
        # so "press any key" prompts work in a line-oriented MUD client.
        return 13

    def feed(self, text: str):
        self._input_queue.put(text)
        self._ready.set()


class MudFilesystem(zfilesystem.ZFilesystem):
    def __init__(self, save_path: Path):
        self.save_path = save_path

    def save_game(self, data, suggested_filename=None):
        try:
            self.save_path.parent.mkdir(parents=True, exist_ok=True)
            self.save_path.write_bytes(data)
            return True
        except Exception as e:
            logger.error(f"Failed to save game: {e}")
            return False

    def restore_game(self):
        if self.save_path.exists():
            try:
                return self.save_path.read_bytes()
            except Exception as e:
                logger.error(f"Failed to restore game: {e}")
                return None
        return None

    def open_transcript_file_for_writing(self):
        return None

    def open_transcript_file_for_reading(self):
        return None


def create_mud_ui(save_path: Path) -> tuple[zui.ZUI, MudScreen, MudInputStream]:
    audio = NullAudio()
    screen = MudScreen()
    keyboard = MudInputStream()
    filesystem = MudFilesystem(save_path)
    ui = zui.ZUI(audio, screen, keyboard, filesystem)
    return ui, screen, keyboard
