# ruff: noqa: RUF001, RUF002, RUF003
"""Tests for auto_yes._ansi module."""

from auto_yes._ansi import clean_text, strip_ansi, strip_control
from auto_yes.detector import PromptDetector


class TestStripAnsi:
    def test_plain_text_unchanged(self):
        assert strip_ansi("hello world") == "hello world"

    def test_removes_color_codes(self):
        colored = "\x1b[31mERROR\x1b[0m: something broke"
        assert strip_ansi(colored) == "ERROR: something broke"

    def test_removes_cursor_movement(self):
        text = "\x1b[2J\x1b[HWelcome"
        assert strip_ansi(text) == "Welcome"

    def test_removes_osc_sequences(self):
        text = "\x1b]0;My Title\x07some content"
        assert strip_ansi(text) == "some content"

    def test_empty_string(self):
        assert strip_ansi("") == ""

    # --- cursor-forward expansion (Claude Code ≥ 2.x TUI rendering) ---

    def test_cursor_forward_1_becomes_space(self):
        """ESC[1C (cursor-forward-1) → single space."""
        text = "\x1b[1Chello"
        assert strip_ansi(text) == " hello"

    def test_cursor_forward_n_becomes_n_spaces(self):
        """ESC[3C → three spaces."""
        text = "\x1b[3Cindented"
        assert strip_ansi(text) == "   indented"

    def test_cursor_forward_no_arg_becomes_space(self):
        """ESC[C (no number) → single space (default is 1)."""
        assert strip_ansi("\x1b[Cword") == " word"

    def test_cursor_forward_words_spaced(self):
        """TUI word spacing: ❯\x1b[1C1.\x1b[1CYes → '❯ 1. Yes'."""
        text = "❯\x1b[1C1.\x1b[1CYes"
        result = strip_ansi(text)
        assert result == "❯ 1. Yes"

    def test_real_claude_2_trust_line(self):
        """Real Claude Code 2.x trust-folder line (raw bytes)."""
        raw = (
            b"\x1b[1C\x1b[38;5;153m\xe2\x9d\xaf"  # ❯ (with color)
            b"\x1b[1C\x1b[38;5;246m1."              # 1.
            b"\x1b[1C\x1b[38;5;153mYes,"            # Yes,
            b"\x1b[1CI"                              # I
            b"\x1b[1Ctrust"                          # trust
            b"\x1b[1Cthis"                           # this
            b"\x1b[1Cfolder\x1b[39m"                 # folder
        )
        text = raw.decode("utf-8")
        result = strip_ansi(text)
        assert "❯ 1. Yes, I trust this folder" in result


class TestStripControl:
    def test_preserves_newlines_and_cr(self):
        text = "line1\nline2\rline3"
        assert strip_control(text) == "line1\nline2\rline3"

    def test_removes_bell_and_backspace(self):
        text = "he\x07llo\x08"
        assert strip_control(text) == "hello"


class TestCleanText:
    def test_ansi_and_cr_combined(self):
        raw = "\x1b[32mpartial\rDo you want to continue? [y/n]\x1b[0m"
        result = clean_text(raw)
        assert "Do you want to continue? [y/n]" in result
        assert "\x1b" not in result

    def test_carriage_return_overwrites(self):
        raw = "old text\rnew text"
        assert clean_text(raw) == "new text"

    def test_multiline_preserved(self):
        raw = "line 1\nline 2\nline 3"
        assert clean_text(raw) == "line 1\nline 2\nline 3"

    def test_trailing_cr_preserves_content(self):
        """Lines ending with bare \\r (from \\r\\r\\n terminators) keep content."""
        # Claude Code 2.x TUI emits \r\r\n as line terminator.
        # After replace("\r\n", "\n") this leaves a trailing \r on each line.
        raw = "hello world\r"
        assert clean_text(raw) == "hello world"

    def test_double_crlf_terminator(self):
        """\\r\\r\\n terminator (Claude Code TUI) keeps line content."""
        raw = "❯ 1. Yes, I trust this folder\r\r\n2. No, exit\r\r\n"
        result = clean_text(raw)
        assert "❯ 1. Yes, I trust this folder" in result
        assert "2. No, exit" in result

    def test_real_claude2_trust_dialog(self):
        """Full real Claude Code 2.x trust dialog detected after both fixes."""
        raw_bytes = (
            b"\r\n\r\r\n"
            b"\x1b[1C\x1b[38;5;153m\xe2\x9d\xaf"
            b"\x1b[1C\x1b[38;5;246m1."
            b"\x1b[1C\x1b[38;5;153mYes,"
            b"\x1b[1CI\x1b[1Ctrust\x1b[1Cthis\x1b[1Cfolder\x1b[39m"
            b"\r\r\n"
            b"\x1b[3C\x1b[38;5;246m2.\x1b[1C\x1b[39mNo,\x1b[1Cexit"
            b"\r\r\n\r\r\n"
            b"\x1b[1C\x1b[38;5;246mEnter\x1b[1Cto\x1b[1Cconfirm"
            b"\x1b[1C\xc2\xb7\x1b[1CEsc\x1b[1Cto\x1b[1Ccancel\x1b[39m"
        )
        text = raw_bytes.decode("utf-8")
        result = clean_text(text)
        assert "❯ 1. Yes, I trust this folder" in result
        assert "2. No, exit" in result

    def test_real_claude2_trust_dialog_detected(self):
        """Detector finds trust-folder match in real Claude Code 2.x output."""
        raw_bytes = (
            b"\r\n\r\r\n"
            b"\x1b[1C\x1b[38;5;153m\xe2\x9d\xaf"
            b"\x1b[1C\x1b[38;5;246m1."
            b"\x1b[1C\x1b[38;5;153mYes,"
            b"\x1b[1CI\x1b[1Ctrust\x1b[1Cthis\x1b[1Cfolder\x1b[39m"
            b"\r\r\n"
            b"\x1b[3C\x1b[38;5;246m2.\x1b[1C\x1b[39mNo,\x1b[1Cexit"
            b"\r\r\n\r\r\n"
            b"\x1b[1C\x1b[38;5;246mEnter\x1b[1Cto\x1b[1Cconfirm"
            b"\x1b[1C\xc2\xb7\x1b[1CEsc\x1b[1Cto\x1b[1Ccancel\x1b[39m"
        )
        text = raw_bytes.decode("utf-8")
        det = PromptDetector(categories=["claude"])
        result = det.detect(text)
        assert result is not None
        assert "Yes" in result.pattern or "trust" in result.pattern
