#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------
# Copyright (c) 2026 Huawei Technologies Co., Ltd.
# This file is part of the MindStudio project.
#
# MindStudio is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#    http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# -------------------------------------------------------------------------

from pathlib import Path
from types import SimpleNamespace

import pytest
from prompt_toolkit.formatted_text import to_formatted_text
from prompt_toolkit.formatted_text.utils import fragment_list_to_text

from msagent.cli.core.context import Context
from msagent.cli.ui.prompt import InteractivePrompt
from msagent.cli.ui.shared import build_agent_prompt
from msagent.configs import ApprovalMode


def _build_prompt_context(**overrides) -> Context:
    data = {
        "agent": "general",
        "model": "default",
        "thread_id": "thread-1",
        "working_dir": Path.cwd(),
        "approval_mode": ApprovalMode.SEMI_ACTIVE,
        "recursion_limit": 80,
        "current_input_tokens": 6000,
        "current_output_tokens": 2000,
        "context_window": 64000,
    }
    data.update(overrides)
    return Context(**data)


def test_bottom_toolbar_shows_ctx_and_token_breakdown() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context()
    prompt._show_quit_message = False

    usage = fragment_list_to_text(to_formatted_text(prompt._get_bottom_toolbar()))

    assert "[ctx 8K/64K tokens (13%) | in 6K | out 2K]" in usage
    assert "$" not in usage


def test_bottom_toolbar_hides_usage_without_input_tokens() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context(current_input_tokens=None)
    prompt._show_quit_message = False

    usage = fragment_list_to_text(to_formatted_text(prompt._get_bottom_toolbar()))

    assert "ctx " not in usage
    assert " in " not in usage
    assert " out " not in usage


def test_placeholder_text_uses_current_agent_name() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context(agent="Profiler")

    text = prompt._build_placeholder_text()

    assert text == "尽管问Profiler,@ 引用文件,/ 使用命令"


def test_placeholder_text_stays_consistent_in_bash_mode() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context(agent="general", bash_mode=True)

    text = prompt._build_placeholder_text()

    assert text == "尽管问general,@ 引用文件,/ 使用命令"


def test_prompt_hotkeys_include_tool_output_toggle() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context()
    prompt.commands = ["/help", "/tool-output"]
    prompt.session = SimpleNamespace(prefilled_text=None)
    prompt.hotkeys = {}

    prompt._create_key_bindings()

    assert "Ctrl+O" in prompt.hotkeys
    assert prompt.hotkeys["Ctrl+O"] == "Expand/collapse latest tool output"


def test_build_agent_prompt_uses_current_agent_name() -> None:
    prompt_text = build_agent_prompt(_build_prompt_context(agent="Profiler"))

    assert prompt_text == "Profiler > "


@pytest.mark.asyncio
async def test_get_input_disables_prompt_toolkit_sigint_handling() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt.context = _build_prompt_context()
    prompt.commands = ["/help"]
    prompt.session = SimpleNamespace(prefilled_text=None)

    captured: dict[str, object] = {}

    class FakePromptSession:
        async def prompt_async(self, *args, **kwargs):
            captured["args"] = args
            captured["kwargs"] = kwargs
            return "/help"

    prompt.prompt_session = FakePromptSession()

    content, is_command = await prompt.get_input()

    assert content == "/help"
    assert is_command is True
    assert captured["args"][0][0][1] == "general > "
    assert captured["kwargs"]["handle_sigint"] is False


def test_handle_external_sigint_shows_quit_hint_when_prompt_is_running() -> None:
    prompt = InteractivePrompt.__new__(InteractivePrompt)
    prompt._last_ctrl_c_time = None
    prompt._ctrl_c_timeout = 0.30
    prompt._show_quit_message = False
    scheduled = {}

    class FakeBuffer:
        text = ""

    class FakeApp:
        is_running = True
        current_buffer = FakeBuffer()

        class loop:
            @staticmethod
            def call_later(delay, callback):
                scheduled["delay"] = delay
                scheduled["callback"] = callback

        def invalidate(self):
            scheduled["invalidated"] = True

        def exit(self, exception=None):
            scheduled["exit_exception"] = exception

    prompt.prompt_session = SimpleNamespace(app=FakeApp())

    handled = prompt.handle_external_sigint()

    assert handled is True
    assert prompt._show_quit_message is True
    assert scheduled["delay"] == 0.30
    assert scheduled["invalidated"] is True
    assert "exit_exception" not in scheduled