import asyncio

from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph
from pydantic import BaseModel


# Define the data structure (state) passed between nodes in the graph
class ResearchState(BaseModel):
    query: str  # The original research query
    raw_info: str = ""  # Raw fetched or mocked information
    summary: str = ""  # Final summarized result


# Function to create and return the research agent graph
def get_research_agent(model="gpt-4o", base_url=None):
    # Initialize the OpenAI LLM with the specified model and API key
    llm = ChatOpenAI(model=model, base_url=base_url)

    # Create a stateful graph with ResearchState as the shared state type
    graph = StateGraph(ResearchState)

    # Node 1: Simulate a search function that populates raw_info
    def search_info(state: ResearchState) -> ResearchState:
        # TODO: Replace with real search API integration
        mock_info = f"(Mock) According to recent sources, the latest trends in {state.query} include X, Y, Z."
        return ResearchState(query=state.query, raw_info=mock_info)

    # Node 2: Use the LLM to summarize the raw_info content
    def summarize_info(state: ResearchState) -> ResearchState:
        prompt = f"Summarize the following:\n{state.raw_info}"
        response = llm.invoke(prompt)  # Call the LLM to get the summary
        return ResearchState(
            query=state.query, raw_info=state.raw_info, summary=response.text
        )

    # Node 3: Format the final summary for output
    def output_summary(state: ResearchState) -> ResearchState:
        final_summary = f"Research summary for '{state.query}': {state.summary}"
        return ResearchState(
            query=state.query, raw_info=state.raw_info, summary=final_summary
        )

    # Add nodes to the graph
    graph.add_node("search_info", search_info)
    graph.add_node("summarize_info", summarize_info)
    graph.add_node("output_summary", output_summary)

    # Define the flow between nodes (edges)
    graph.add_edge("search_info", "summarize_info")
    graph.add_edge("summarize_info", "output_summary")

    # Set the starting and ending points of the graph
    graph.set_entry_point("search_info")
    graph.set_finish_point("output_summary")

    # Compile the graph into an executable app
    return graph.compile()


# Function to run the research agent with a given query prompt
def run_research_agent(prompt, model="gpt-4o", base_url=None):
    # Get the compiled graph application
    app = get_research_agent(model=model, base_url=base_url)
    # Run the asynchronous invocation and get the result
    result = asyncio.run(app.ainvoke(ResearchState(query=prompt)))
    return result
