from typing import Dict, Any, Optional
from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import (
    BaseToolResolver,
)
from autocoder.common.v2.agent.agentic_edit_types import (
    AskFollowupQuestionTool,
    ToolResult,
)  # Import ToolResult from types
from loguru import logger
import typing
import asyncio
from concurrent.futures import ThreadPoolExecutor
from autocoder.common import AutoCoderArgs
from autocoder.run_context import get_run_context
from autocoder.events.event_manager_singleton import get_event_manager
from autocoder.events import event_content as EventContentCreator
from autocoder.common.async_prompt import PromptSession
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from autocoder.common.result_manager import ResultManager
from autocoder.common.printer import Printer

if typing.TYPE_CHECKING:
    from autocoder.common.v2.agent.agentic_edit import AgenticEdit

# 用于 terminal 模式超时的线程池
_timeout_executor = ThreadPoolExecutor(
    max_workers=1, thread_name_prefix="ask_user_timeout"
)


class AskFollowupQuestionToolResolver(BaseToolResolver):
    def __init__(
        self,
        agent: Optional["AgenticEdit"],
        tool: AskFollowupQuestionTool,
        args: AutoCoderArgs,
    ):
        super().__init__(agent, tool, args)
        self.tool: AskFollowupQuestionTool = tool  # For type hinting
        self.result_manager = ResultManager()
        self.printer = Printer()

    def _prompt_with_timeout(self, timeout_seconds: float) -> str:
        """
        在独立的事件循环中运行 prompt_async 并应用超时。
        如果超时则返回空字符串。
        """

        async def _inner() -> str:
            from prompt_toolkit import PromptSession as _RawPromptSession

            session = _RawPromptSession(
                message=self.printer.get_message_from_key("tool_ask_user")
            )
            return await asyncio.wait_for(
                session.prompt_async(), timeout=timeout_seconds
            )

        # 在新线程中创建全新的事件循环来运行 prompt_async，
        # 避免与调用方可能存在的 running loop 冲突
        future = _timeout_executor.submit(asyncio.run, _inner())
        try:
            return future.result()
        except asyncio.TimeoutError:
            logger.warning(f"Terminal prompt timed out after {timeout_seconds}s")
            return ""
        except Exception as e:
            logger.warning(
                f"Terminal prompt with timeout failed ({e}), falling back to blocking prompt"
            )
            # 降级：使用普通阻塞 prompt（无超时）
            session = PromptSession(
                message=self.printer.get_message_from_key("tool_ask_user")
            )
            try:
                return session.prompt()
            except KeyboardInterrupt:
                return ""

    def resolve(self) -> ToolResult:
        """
        Packages the question and options to be handled by the main loop/UI.
        This resolver doesn't directly ask the user but prepares the data for it.
        Supports optional timeout via args.ask_user_timeout_seconds.
        """
        # Check if running in CLI mode, if so return immediately with a message
        # instructing the model to solve the problem on its own
        if get_run_context().is_cli() or self.agent.args.enable_agentic_auto_approve:
            return ToolResult(
                success=False,
                message="Remember, you cannot ask follow-up questions. Please try to solve the problem on your own using the available information. Do not give up and do your best to find a solution.",
            )

        question = self.tool.question
        options = self.tool.options or []
        options_text = "\n".join(
            [f"{i+1}. {option}" for i, option in enumerate(options)]
        )

        # 统一的超时来源
        timeout_seconds: Optional[float] = self.args.ask_user_timeout_seconds

        if get_run_context().is_web():
            answer = get_event_manager(self.args.event_file).ask_user(
                prompt=question, timeout=timeout_seconds
            )
            self.result_manager.append(
                content=answer + ("\n" + options_text if options_text else ""),
                meta={"action": "ask_user", "input": {"question": question}},
            )
            if not answer:
                return ToolResult(
                    success=False,
                    message=(
                        "I did not have time to answer your question. you can decide to how to handle this situation by yourself or ask me to answer the question later."
                        if timeout_seconds is not None
                        else "Error: Question not answered."
                    ),
                    content="",
                )
            return ToolResult(
                success=True, message="Follow-up question prepared.", content=answer
            )

        console = Console()

        # 创建一个醒目的问题面板
        question_text = Text(question, style="bold cyan")
        question_panel = Panel(
            question_text,
            title="[bold yellow]auto-coder.chat's Question[/bold yellow]",
            border_style="blue",
            expand=False,
        )

        # 显示问题面板
        console.print(question_panel)

        if timeout_seconds is not None:
            console.print(f"[dim](timeout: {timeout_seconds}s)[/dim]")

        try:
            if timeout_seconds is not None:
                answer = self._prompt_with_timeout(timeout_seconds)
            else:
                session = PromptSession(
                    message=self.printer.get_message_from_key("tool_ask_user")
                )
                answer = session.prompt()
        except KeyboardInterrupt:
            answer = ""

        # The actual asking logic resides outside the resolver, typically in the agent's main loop
        # or UI interaction layer. The resolver's job is to validate and package the request.
        if not answer:
            return ToolResult(
                success=False,
                message=(
                    "I did not have time to answer your question. you can decide to how to handle this situation by yourself or ask me to answer the question later."
                    if timeout_seconds is not None
                    else "Error: Question not answered."
                ),
            )

        # Indicate success in preparing the question data
        return ToolResult(
            success=True, message="Follow-up question prepared.", content=answer
        )
