# Copyright (c) Microsoft. All rights reserved.

"""
Demonstrate a workflow that responds to user input using an agent with
function tools assigned. Exits the loop when the user enters "exit".
"""

import asyncio
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Annotated, Any

from agent_framework import Agent, FileCheckpointStorage, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework_declarative import ExternalInputRequest, ExternalInputResponse, WorkflowFactory
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field

# Load environment variables from .env file
load_dotenv()

TEMP_DIR = Path(__file__).with_suffix("").parent / "tmp" / "checkpoints"
TEMP_DIR.mkdir(parents=True, exist_ok=True)


@dataclass
class MenuItem:
    category: str
    name: str
    price: float
    is_special: bool = False


MENU_ITEMS = [
    MenuItem(category="Soup", name="Clam Chowder", price=4.95, is_special=True),
    MenuItem(category="Soup", name="Tomato Soup", price=4.95, is_special=False),
    MenuItem(category="Salad", name="Cobb Salad", price=9.99, is_special=False),
    MenuItem(category="Salad", name="House Salad", price=4.95, is_special=False),
    MenuItem(category="Drink", name="Chai Tea", price=2.95, is_special=True),
    MenuItem(category="Drink", name="Soda", price=1.95, is_special=False),
]


# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_menu() -> list[dict[str, Any]]:
    """Get all menu items."""
    return [{"category": i.category, "name": i.name, "price": i.price} for i in MENU_ITEMS]


@tool(approval_mode="never_require")
def get_specials() -> list[dict[str, Any]]:
    """Get today's specials."""
    return [{"category": i.category, "name": i.name, "price": i.price} for i in MENU_ITEMS if i.is_special]


@tool(approval_mode="never_require")
def get_item_price(name: Annotated[str, Field(description="Menu item name")]) -> str:
    """Get price of a menu item."""
    for item in MENU_ITEMS:
        if item.name.lower() == name.lower():
            return f"${item.price:.2f}"
    return f"Item '{name}' not found."


async def main():
    # Create agent with tools
    client = FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ["FOUNDRY_MODEL"],
        credential=AzureCliCredential(),
    )
    menu_agent = Agent(
        client=client,
        name="MenuAgent",
        instructions="Answer questions about menu items, specials, and prices.",
        tools=[get_menu, get_specials, get_item_price],
    )

    # Clean up any existing checkpoints
    for file in TEMP_DIR.glob("*"):
        file.unlink()

    factory = WorkflowFactory(checkpoint_storage=FileCheckpointStorage(TEMP_DIR))
    factory.register_agent("MenuAgent", menu_agent)
    workflow = factory.create_workflow_from_yaml_path(Path(__file__).parent / "workflow.yaml")

    # Get initial input
    print("Restaurant Menu Assistant (type 'exit' to quit)\n")
    user_input = input("You: ").strip()  # noqa: ASYNC250
    if not user_input:
        return

    # Run workflow with external loop handling
    pending_request_id: str | None = None
    first_response = True

    while True:
        if pending_request_id:
            response = ExternalInputResponse(user_input=user_input)
            stream = workflow.run(stream=True, responses={pending_request_id: response})
        else:
            stream = workflow.run({"userInput": user_input}, stream=True)

        pending_request_id = None
        first_response = True

        async for event in stream:
            if event.type == "output" and isinstance(event.data, str):
                if first_response:
                    print("MenuAgent: ", end="")
                    first_response = False
                print(event.data, end="", flush=True)
            elif event.type == "request_info" and isinstance(event.data, ExternalInputRequest):
                pending_request_id = event.request_id

        print()

        if not pending_request_id:
            break

        user_input = input("\nYou: ").strip()
        if not user_input:
            continue


if __name__ == "__main__":
    asyncio.run(main())
