# -*- coding: utf-8 -*-
"""
回归测试：Windows IME 提交 CJK 字符时，首字符不能被吞。

复现：用户输入"你好"，终端只显示"> 好"，"你"被吞掉。
根因：Windows IME 偶尔以两字节序列 \\x00 + CJK字符 提交首字符，
      ansi_prompt 的特殊键分支（key == '\\x00'）读到 CJK 字符后不匹配任何箭头键，
      直接 continue 丢弃，导致首字符被吞。
"""
import io
import sys
from unittest.mock import patch

import pytest

from abyss.ansi_menu import ansi_prompt


def _make_key_sequence(keys):
    """将字符列表转成 getwch 的逐次返回值生成器。"""
    gen = iter(keys)

    def _mock_getwch():
        try:
            return next(gen)
        except StopIteration:
            raise OSError("输入耗尽")

    return _mock_getwch


class TestIMEFirstCharNotSwallowed:
    """验证 IME 以 \\x00 + CJK 提交首字符时，首字符不被吞。"""

    @patch('msvcrt.getwch')
    @patch('sys.platform', 'win32')
    @patch('ctypes.windll')
    def test_ime_two_byte_cjk_first_char_survives(self, _mock_windll, mock_getwch):
        """IME 发送 \\x00 + '你' + '好' + Enter：结果必须是"你好"，不是"好"。

        红：当前 \\x00 分支读到 '你' 不匹配箭头键，continue 丢弃 → 只剩"好"。
        绿：修复后 \\x00 分支识别 '你' 是可打印 CJK，作为普通字符插入 → "你好"。
        """
        # 模拟 IME 提交：\x00 + '你'（两字节序列），然后 '好'，然后 Enter
        mock_getwch.side_effect = _make_key_sequence(
            ['\x00', '你', '好', '\r']
        )

        buf = io.StringIO()
        old_stdout = sys.stdout
        sys.stdout = buf
        try:
            result = ansi_prompt("> ")
        finally:
            sys.stdout = old_stdout

        assert result == "你好", (
            f"IME 首字符被吞！预期 '你好'，实际 '{result}'\n"
            f"终端输出: {buf.getvalue()!r}"
        )

    @patch('msvcrt.getwch')
    @patch('sys.platform', 'win32')
    @patch('ctypes.windll')
    def test_normal_cjk_input_still_works(self, _mock_windll, mock_getwch):
        """正常 CJK 输入（无 \\x00 前缀）不受影响。"""
        mock_getwch.side_effect = _make_key_sequence(
            ['你', '好', '\r']
        )

        buf = io.StringIO()
        old_stdout = sys.stdout
        sys.stdout = buf
        try:
            result = ansi_prompt("> ")
        finally:
            sys.stdout = old_stdout

        assert result == "你好", f"正常 CJK 输入应返回 '你好'，实际 '{result}'"

    @patch('msvcrt.getwch')
    @patch('sys.platform', 'win32')
    @patch('ctypes.windll')
    def test_arrow_keys_still_work_after_fix(self, _mock_windll, mock_getwch):
        """修复后真正的箭头键（\\x00 + 'H'/'P'/'K'/'M'）仍正常处理。"""
        # 输入 'a' → 左箭头（\x00+'K'）→ 'b' → Enter
        # 预期：左箭头移动光标，'b' 插入在 'a' 前面 → "ba"
        mock_getwch.side_effect = _make_key_sequence(
            ['a', '\x00', 'K', 'b', '\r']
        )

        buf = io.StringIO()
        old_stdout = sys.stdout
        sys.stdout = buf
        try:
            result = ansi_prompt("> ")
        finally:
            sys.stdout = old_stdout

        assert result == "ba", (
            f"箭头键处理后应得 'ba'，实际 '{result}'\n"
            f"终端输出: {buf.getvalue()!r}"
        )
