import os
import asyncio
from typing import Any, AsyncGenerator
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage, ToolMessage
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, MessagesState
from pydantic import PrivateAttr

from .config import get_config
from .db import save_message
from .tools.hello_tool import MerhabaTool
from .tools.mongodb_chat_history_tool import MongoChatHistoryTool
from .tools.mongodb_user_query_tool import MongoDBTool
from .tools.web_search_tool import WebAraTool
from .tools.website_summary_tool import SiteIncelemeTool
from .tools.web_search_and_summary_tool import WebAraVeOzetTool
from .tools.date_time_tool import tarih_ver

config = get_config()

llm = ChatOllama(
    model=config.get("OLLAMA_MODEL"),
    temperature=0.7, 
    keep_alive=config.get("OLLAMA_KEEPALIVE"),
    num_ctx=8192,
    num_predict=1024,    
    top_p=0.9,
    repeat_penalty=1.1,
)

basic_tools = [
    WebAraTool(),
    MongoChatHistoryTool(),
    MongoDBTool(),
    MerhabaTool(),
    tarih_ver,
]

react_agent = create_react_agent(model=llm, tools=basic_tools, prompt=config.get("SYSTEM_PROMPT"))
site_inceleme_tool = SiteIncelemeTool(agent=react_agent)
web_ozet_tool = WebAraVeOzetTool(agent=react_agent)
tools = basic_tools + [site_inceleme_tool, web_ozet_tool]

memory = MemorySaver()
react_agent = create_react_agent(model=llm, tools=tools, prompt=config.get("SYSTEM_PROMPT"))
graph = StateGraph(MessagesState)
graph.add_node("agent", react_agent)
graph.set_entry_point("agent")
app_graph = graph.compile(checkpointer=memory)

async def stream_llm(thread_id: str, prompt: str) -> AsyncGenerator[str, None]:
    await save_message(thread_id, "human", prompt)
    user_msg = HumanMessage(content=prompt)
    last_text = ""
    seen_tool_names = set()

    try:
        async for event in app_graph.astream_events(
            {"messages": [user_msg]},
            config={"configurable": {"thread_id": thread_id}},
            version="v1"
        ):
            kind = event["event"]
            data = event["data"]
            
            if kind == "on_tool_start":
                tool_name = data.get("name", "?")
                if tool_name not in seen_tool_names:
                    seen_tool_names.add(tool_name)
                    yield f"\n📡 Araç çağırılıyor: {tool_name}\n"

            elif kind == "on_llm_stream":
                chunk = data.get("chunk")
                if isinstance(chunk, AIMessage):
                    content = chunk.content
                    if isinstance(content, str) and content.strip():
                        last_text = content
                        yield content
    except Exception as e:
        yield f"\n[❌ Hata] {e}\n"

    finally:
        if last_text.strip():
            await save_message(thread_id, "ai", last_text)
            yield "\n🧠 Cevap tamamlandı\n"