# -*- coding: utf-8 -*-
"""
ansi_menu 视觉辅助函数测试：
- ansi_green_bold / ansi_cyan / ansi_gray_line
- ansi_prompt 的 prompt_color 参数
"""
import os
from unittest.mock import patch

import pytest

from abyss.ansi_menu import (
    ansi_green_bold,
    ansi_cyan,
    ansi_gray_line,
    ansi_prompt,
)


# ─── 颜色包装函数 ────────────────────────────────────────
class TestAnsiColorHelpers:
    def test_ansi_green_bold_wraps_with_codes(self):
        s = ansi_green_bold(">")
        assert "\x1b[1;32m" in s
        assert "\x1b[0m" in s
        assert ">" in s

    def test_ansi_green_bold_preserves_content(self):
        s = ansi_green_bold("hello")
        # 去掉所有 ANSI 转义后应等于原内容
        import re
        plain = re.sub(r"\x1b\[[0-9;]*m", "", s)
        assert plain == "hello"

    def test_ansi_cyan_wraps_with_codes(self):
        s = ansi_cyan("text")
        assert "\x1b[36m" in s
        assert "\x1b[0m" in s
        assert "text" in s

    def test_ansi_cyan_preserves_content(self):
        s = ansi_cyan("world")
        import re
        plain = re.sub(r"\x1b\[[0-9;]*m", "", s)
        assert plain == "world"


# ─── 灰色分隔线 ──────────────────────────────────────────
class TestAnsiGrayLine:
    def test_default_contains_gray_code_and_horizontal_char(self):
        line = ansi_gray_line()
        assert "\x1b[90m" in line
        assert "\x1b[0m" in line
        assert "─" in line

    def test_default_length_within_bounds(self):
        """默认宽度应在 [20, 60] 之间。"""
        line = ansi_gray_line()
        # 计算实际 ─ 的数量
        count = line.count("─")
        assert 20 <= count <= 60

    def test_custom_width(self):
        line = ansi_gray_line(width=15)
        assert line.count("─") == 15

    def test_zero_or_negative_width_falls_back_to_auto(self):
        """width<=0 时自动取终端宽度（夹在 20-60）。"""
        line = ansi_gray_line(width=0)
        count = line.count("─")
        assert 20 <= count <= 60

    def test_terminal_width_capped_at_60(self):
        """终端很宽时分隔线不超过 60。"""
        with patch("os.get_terminal_size") as mock_ts:
            mock_ts.return_value = os.terminal_size((200, 50))
            line = ansi_gray_line()
            assert line.count("─") == 60

    def test_terminal_width_floored_at_20(self):
        """终端很窄时分隔线至少 20。"""
        with patch("os.get_terminal_size") as mock_ts:
            mock_ts.return_value = os.terminal_size((10, 5))
            line = ansi_gray_line()
            assert line.count("─") == 20

    def test_terminal_size_failure_falls_back_to_80(self):
        """os.get_terminal_size 抛异常时回退到 80 列（min(60, 80)=60）。"""
        with patch("os.get_terminal_size", side_effect=OSError):
            line = ansi_gray_line()
            assert line.count("─") == 60


# ─── ansi_prompt prompt_color 参数 ──────────────────────
class TestAnsiPromptColor:
    """ansi_prompt 接受 prompt_color 参数：渲染时包裹颜色，buffer 仍存纯文本，
    返回值不含任何 ANSI 码。"""

    def _feed_keys(self, keys):
        """构造一个 msvcrt.getwch 的 mock，依次返回 keys 中每个字符。"""
        seq = list(keys)
        import itertools
        counter = {"i": 0}

        def fake_getwch():
            if counter["i"] >= len(seq):
                # 防止无限循环：持续返回 \r
                return "\r"
            ch = seq[counter["i"]]
            counter["i"] += 1
            return ch
        return fake_getwch

    def test_prompt_color_renders_colored_prefix(self, capsys):
        """传入 prompt_color，stdout 应包含颜色化的提示符。"""
        keys = "hi\r"
        with patch("msvcrt.getwch", side_effect=self._feed_keys(keys)):
            with patch("msvcrt.kbhit", return_value=False):
                result = ansi_prompt("> ", prompt_color="\x1b[1;32m")
        out = capsys.readouterr().out
        # 渲染时应包含绿色粗体码 + 提示符 + 复位码
        assert "\x1b[1;32m> \x1b[0m" in out or "\x1b[1;32m>" in out
        # 返回值不含 ANSI 码
        assert result == "hi"

    def test_prompt_color_return_excludes_color(self, capsys):
        """返回值应为纯用户输入，不含 ANSI 码。"""
        keys = "hello\r"
        with patch("msvcrt.getwch", side_effect=self._feed_keys(keys)):
            with patch("msvcrt.kbhit", return_value=False):
                result = ansi_prompt("> ", prompt_color="\x1b[1;32m")
        assert "\x1b" not in result
        assert result == "hello"

    def test_no_color_default_behavior(self, capsys):
        """不传 prompt_color 时，行为与原版一致（无颜色码）。"""
        keys = "ok\r"
        with patch("msvcrt.getwch", side_effect=self._feed_keys(keys)):
            with patch("msvcrt.kbhit", return_value=False):
                result = ansi_prompt("> ")
        out = capsys.readouterr().out
        assert result == "ok"
        # 默认不传颜色时，stdout 不应包含绿色码
        assert "\x1b[1;32m" not in out
