import asyncio
import os
from dataclasses import dataclass

from dotenv import load_dotenv
from typing_extensions import Never

from agent_framework import Agent, Executor, WorkflowBuilder, WorkflowContext, handler
from agent_framework.openai import OpenAIChatClient

load_dotenv()

_INTENT_SYSTEM_PROMPT = """\
You are given a list of orders with item_numbers from a customer and a statement from the customer. \
It is your job to identify the intent that the customer has with their statement. \
Possible intents can be: "product return", "product exchange", "general question", "product question", "other"."""

_INTENT_USER_TEMPLATE = """\
In triple backticks below is the customer information and a list of orders.

```
{customer_info}
```

In triple backticks below are the is the chat history with customer \
statements and replies from the customer service agent:

```
{history}
```

What is the customer's `intent:` here?

"product return", "exchange product", "general question", "product question" or "other"?

Reply with only the intent string."""


@dataclass
class IntentInput:
    history: str
    customer_info: str


class PromptExecutor(Executor):
    @handler
    async def receive(self, intent_input: IntentInput, ctx: WorkflowContext[str]) -> None:
        prompt = _INTENT_USER_TEMPLATE.format(
            customer_info=intent_input.customer_info,
            history=intent_input.history,
        )
        await ctx.send_message(prompt)


class ExtractIntentExecutor(Executor):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        client = OpenAIChatClient(
            azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
            model=os.environ["AZURE_OPENAI_DEPLOYMENT"],
            api_key=os.environ["AZURE_OPENAI_API_KEY"],
        )
        self._agent = Agent(
            client=client,
            name="IntentAgent",
            instructions=_INTENT_SYSTEM_PROMPT,
        )

    @handler
    async def extract(self, prompt: str, ctx: WorkflowContext[Never, str]) -> None:
        response = await self._agent.run(prompt)
        await ctx.yield_output(response.text)


def create_workflow():
    """Create a fresh workflow instance.

    MAF workflows do not support concurrent execution, so each
    concurrent caller needs its own workflow instance.
    """
    _prompt = PromptExecutor(id="chat_prompt")
    _extract = ExtractIntentExecutor(id="extract_intent")
    return (
        WorkflowBuilder(name="CustomerIntentWorkflow", start_executor=_prompt)
        .add_edge(_prompt, _extract)
        .build()
    )


async def main():
    workflow = create_workflow()
    result = await workflow.run(
        IntentInput(
            history="Customer: I want to return my order\nAgent: Sure, I can help with that.",
            customer_info="Name: John Doe\nOrder: #12345 - Widget A",
        )
    )
    print(f"Intent: {result.get_outputs()[0]}")


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