from __future__ import annotations

import asyncio
import os
import signal
import sys
import termios
import tty
from threading import Thread

from textual import events
from textual.driver import Driver
from textual.geometry import Size
from textual.messages import TerminalSupportInBandWindowResize


def build_driver_class() -> type[Driver] | None:
    """Return an opt-in compatibility driver for problematic terminals.

    Textual's stock driver is the default because it is the best-tested path.
    The compatibility driver remains available behind an env flag for targeted
    debugging only.
    """

    if os.getenv("YOUR_APP_ENABLE_COMPAT_DRIVER", "").lower() not in {"1", "true", "yes"}:
        return None

    if sys.platform.startswith("win"):
        return None

    from textual.drivers._writer_thread import WriterThread
    from textual.drivers.linux_driver import LinuxDriver

    class CompatLinuxDriver(LinuxDriver):
        """Terminal driver with advanced terminal features disabled.

        This avoids terminal-specific issues around Kitty keyboard mode,
        mouse tracking, sync mode probing, and bracketed paste.
        """

        def start_application_mode(self) -> None:
            def _stop_again(*_) -> None:
                os.kill(os.getpid(), signal.SIGSTOP)

            if os.isatty(self.fileno):
                signal.signal(signal.SIGTTOU, _stop_again)
                signal.signal(signal.SIGTTIN, _stop_again)
                try:
                    termios.tcsetattr(
                        self.fileno, termios.TCSANOW, termios.tcgetattr(self.fileno)
                    )
                except termios.error:
                    return
                finally:
                    signal.signal(signal.SIGTTOU, signal.SIG_DFL)
                    signal.signal(signal.SIGTTIN, signal.SIG_DFL)

            loop = asyncio.get_running_loop()

            def send_size_event() -> None:
                width, height = self._get_terminal_size()
                textual_size = Size(width, height)
                event = events.Resize(textual_size, textual_size)
                asyncio.run_coroutine_threadsafe(self._app._post_message(event), loop=loop)

            self._writer_thread = WriterThread(self._file)
            self._writer_thread.start()

            def on_terminal_resize(signum, stack) -> None:
                if not self._in_band_window_resize:
                    send_size_event()

            signal.signal(signal.SIGWINCH, on_terminal_resize)

            self.write("\x1b[?1049h")

            try:
                self.attrs_before = termios.tcgetattr(self.fileno)
            except termios.error:
                self.attrs_before = None

            try:
                newattr = termios.tcgetattr(self.fileno)
            except termios.error:
                pass
            else:
                newattr[tty.LFLAG] = self._patch_lflag(newattr[tty.LFLAG])
                newattr[tty.IFLAG] = self._patch_iflag(newattr[tty.IFLAG])
                newattr[tty.CC][termios.VMIN] = 1
                try:
                    termios.tcsetattr(self.fileno, termios.TCSANOW, newattr)
                except termios.error:
                    pass

            self.write("\x1b[?25l")
            self.flush()

            self._key_thread = Thread(target=self._run_input_thread)
            send_size_event()
            self._key_thread.start()
            self._disable_line_wrap()

            if self._must_signal_resume:
                self._must_signal_resume = False
                asyncio.run_coroutine_threadsafe(
                    self._app._post_message(self.SignalResume()),
                    loop=loop,
                )

        def stop_application_mode(self) -> None:
            self._enable_line_wrap()
            self.disable_input()

            if self.attrs_before is not None:
                try:
                    termios.tcsetattr(self.fileno, termios.TCSANOW, self.attrs_before)
                except termios.error:
                    pass

            self.write("\x1b[?1049l")
            self.write("\x1b[?25h")
            self.flush()

        def _request_terminal_sync_mode_support(self) -> None:
            return

        def _disable_in_band_window_resize(self) -> None:
            self._in_band_window_resize = False

        async def _on_terminal_supports_in_band_window_resize(
            self, message: TerminalSupportInBandWindowResize
        ) -> None:
            self._in_band_window_resize = False

    return CompatLinuxDriver


def apply_runtime_compatibility() -> None:
    os.environ.setdefault("TEXTUAL_ALLOW_SIGNALS", "1")
    signal.signal(signal.SIGINT, signal.default_int_handler)
