# type: ignore # noqa: F401

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

import sys

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

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]:
    """
    Her prompt için:
    - Önceki tool mesajları gösterilmez
    - AI cevabı tek seferde
    - Düşünüyor animasyonu
    """
    await save_message(thread_id, "human", prompt)
    user_msg = HumanMessage(content=prompt)

    last_text = ""
    animation = ["⠁","⠂","⠄","⡀","⢀","⠠","⠐","⠈"]
    anim_index = 0

    # Bu prompt için görülen tool mesajları
    seen_tool_names = set()

    try:
        async for event in app_graph.astream(
            {"messages": [user_msg], "reset_context": True},  # Temiz context # type: ignore
            config={"configurable": {"thread_id": thread_id}},durability="async",
            stream_mode=["values", "updates"]
        ):
            mode, data = event
            messages = []

            if mode == "values":
                messages = data.get("messages", [])
            elif mode == "updates":
                messages = data.get("agent", {}).get("messages", [])

            if not messages:
                # Düşünüyor animasyonu
                # yield f"{animation[anim_index]} Düşünüyor...\r"
                # anim_index = (anim_index + 1) % len(animation)
                # await asyncio.sleep(0.1)
                continue

            for msg in messages:
                # Tool mesajlarını tekilleştir
                # if isinstance(msg, ToolMessage):
                #     if msg.name in seen_tool_names:
                #         continue
                #     seen_tool_names.add(msg.name)
                #     yield f"[🛠️ Araç Kullanılıyor] {msg.name}\n"
                #     break

                # AI mesajlarını sakla
                if isinstance(msg, AIMessage):
                    if msg.content.strip():
                        last_text = msg.content
                    # else:
                        # Boşsa animasyon göster
                        # yield f"{animation[anim_index]} Düşünüyor...\r"
                        # anim_index = (anim_index + 1) % len(animation)
                        # await asyncio.sleep(0.1)

    except Exception as e:
        yield f"[❌ Beklenmeyen hata: {e}]\n"

    finally:
        if last_text.strip():
            await save_message(thread_id, "ai", last_text)
            yield f"{last_text}\n"
        else:
            yield "\n[🧠 FikoGpt Cevabı] (cevap üretilmedi)\n"
        # yield "[✅ Tamamlandı]\n"
        seen_tool_names.clear()
