# Copyright (c) Microsoft. All rights reserved.

"""Tool approval observer for user confirmation of tool calls.

Detects function_approval_request content items during streaming, displays
approval notifications, and after the stream completes presents one
ChoiceFollowUpQuestion per pending approval request.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from ..app_state import ChoiceFollowUpQuestion, FollowUpAction
from .base import ConsoleObserver

if TYPE_CHECKING:
    from agent_framework import Agent, Content, Message

    from ..state_driver import IUXStateDriver


class ToolApprovalObserver(ConsoleObserver):
    """Asks user to approve tool calls before execution.

    Collects `function_approval_request` content during streaming and presents
    a multi-choice approval question for each after the stream completes.
    The continuation builds a `function_approval_response` Content to inject
    into the next agent turn.
    """

    def __init__(self) -> None:
        """Initialize the tool approval observer."""
        self._approval_requests: list[Content] = []

    async def on_content(
        self,
        ux: IUXStateDriver,
        content: Content,
        agent: Agent,
        session: Any,
    ) -> None:
        """Collect function_approval_request content for approval.

        Args:
            ux: The UX state driver for UI updates.
            content: The content item to check.
            agent: The AI agent.
            session: The agent session.
        """
        if content.type == "function_approval_request":
            self._approval_requests.append(content)
            tool_name = self._format_tool_name(content)
            ux.append_info_line(f"⚠️ Approval needed: {tool_name}", "yellow")

    async def on_stream_complete(
        self,
        ux: IUXStateDriver,
        agent: Agent,
        session: Any,
    ) -> list[FollowUpAction] | None:
        """Build approval questions for collected requests.

        Args:
            ux: The UX state driver for UI updates.
            agent: The AI agent.
            session: The agent session.

        Returns:
            List of ChoiceFollowUpQuestions, one per approval request.
        """
        if not self._approval_requests:
            return None

        actions: list[FollowUpAction] = []
        for request in self._approval_requests:
            actions.append(self._build_approval_question(request))

        self._approval_requests.clear()
        return actions

    def _build_approval_question(self, request: Content) -> ChoiceFollowUpQuestion:
        """Build a multi-choice approval question for a single request."""
        tool_name = self._format_tool_name(request)
        prompt = f"🔐 Tool approval: {tool_name}"

        approve_once = "Approve this call"
        always_tool = "Always approve this tool (any arguments)"
        always_tool_args = "Always approve this tool with these arguments"
        deny = "Deny"
        choices = [approve_once, always_tool, always_tool_args, deny]

        async def continuation(
            selection: str,
            ux: IUXStateDriver,
        ) -> Message | None:
            from agent_framework import (
                Message,
                create_always_approve_tool_response,
                create_always_approve_tool_with_arguments_response,
            )

            if selection == deny:
                response_content = request.to_function_approval_response(approved=False)
                action_label = "❌ Denied"
                color = "red"
            elif selection == always_tool:
                response_content = create_always_approve_tool_response(
                    request, reason="User chose to always approve this tool"
                )
                action_label = "✅ Always approved (any args)"
                color = "green"
            elif selection == always_tool_args:
                response_content = create_always_approve_tool_with_arguments_response(
                    request, reason="User chose to always approve this tool with these arguments"
                )
                action_label = "✅ Always approved (these args)"
                color = "green"
            else:
                response_content = request.to_function_approval_response(approved=True)
                action_label = "✅ Approved"
                color = "green"

            ux.append_info_line(
                f"🔹 {prompt}\n   └─ [{color}]{action_label}[/{color}]",
                "dim",
            )

            return Message(role="user", contents=[response_content])

        return ChoiceFollowUpQuestion(
            prompt=prompt,
            choices=choices,
            allow_custom_text=False,
            continuation=continuation,
        )

    @staticmethod
    def _format_tool_name(content: Content) -> str:
        """Extract a readable tool name from approval request content."""
        # The function_call is stored on the approval request content
        function_call = getattr(content, "function_call", None)
        if function_call is not None:
            from ..formatters import build_default_formatters, format_tool_call

            try:
                return format_tool_call(build_default_formatters(), function_call)
            except (AttributeError, TypeError):
                pass
            # Fall back to name attribute
            name = getattr(function_call, "name", None)
            if name:
                return str(name)
        return "unknown tool"
