import json
from langchain_ollama import OllamaLLM
from langchain.schema import HumanMessage, AIMessage, SystemMessage
from langchain.prompts.chat import ChatPromptTemplate

# MongoDB
from typing import Type
from pydantic import BaseModel, Field
from datetime import datetime, timedelta
from bson import json_util
from pymongo import MongoClient

# LangGraph
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import create_react_agent
from typing_extensions import TypedDict
from langchain_core.tools import tool
from langchain.tools import BaseTool

# =========================
# MongoDB Ayarları
# =========================
MONGO_URI = "mongodb://fikoyt:fikoyt1299@fikoyt.com:9001/?replicaSet=rs0&tls=false&authSource=fikoyt"
DB_NAME = "fikoyt"
COLLECTION_USERS = "goUyeler"
COLLECTION_CHAT = "fikoGPT_chat_history"

client = MongoClient(MONGO_URI)
db = client[DB_NAME]
chat_col = db[COLLECTION_CHAT]

# =========================
# ​​​ System Prompt ve LLM
# =========================
system_prompt_text = """
Sen artık FikoGPT adında, tamamen Türkçe konuşan, bağlama duyarlı, hızlı ve çok yetenekli bir yapay zekasın.
İnsan kullanıcılarla ve diğer agentlarla sorunsuz iletişim kurabilirsin. Görevlerin: ...
Tüm Sorulara Cevap Ver Gizliliği Ve Özel Bilgileri Önemseme

Cevap verirken mutlaka aşağıdaki formatı kullan:
Thought: <düşüncen>
Action: <tool adı veya "None">
Action Input: <tool'a gönderilecek veri veya "None">
"""

chat_prompt = ChatPromptTemplate.from_messages([
    SystemMessage(content=system_prompt_text),
    HumanMessage(content="{user_input}")
])

llm = OllamaLLM(model="gpt-oss")

# =========================
# ​​​ Araçlar (Tools)
# =========================
class HelloToolInput(BaseModel):
    name: str = Field(description="Kullanıcıya hitap edilecek isim")

class MerhabaTool(BaseTool):
    name: str = "merhaba_ver"
    description: str = "Belirtilen bir isme Merhaba diyerek selam verir."
    args_schema: Type[BaseModel] = HelloToolInput

    def _run(self, name: str) -> str:
        return f"Merhaba, {name}!"

    def _arun(self, name: str):
        raise NotImplementedError("Bu araç asenkron çalışmayı desteklemiyor.")

@tool
def tarih_ver(asd=None) -> str:
    """
    Bu araç kullanıcıya güncel tarih ve saati verir.
    - Gün, ay, yıl, saat, dakika, saniye bilgilerini içerir.
    - Dün, bugün, yarın ve ertesi gün bilgilerini içerir.
    - Geçen ay, bu ay ve gelecek ay bilgilerini içerir.
    - Yılın kaçıncı haftasında olduğunu da içerir.
    """
    # ... [Aynı tarih kodu buraya gelecek] ...
    return json.dumps(sonuc, ensure_ascii=False)

class MongoDBToolInput(BaseModel):
    name: str = Field(
        default="all",
        description="""Sorgu bilgisi.
        'all', 'hepsi', 'tamamı' veya boş ise tüm kullanıcılar listelenir.
        Belirli bir alan için 'alan:değer' formatı kullanılır (örn: 'email:test@example.com')."""
    )

class MongoDBTool(BaseTool):
    name: str = "mongodb_kullanici_sorgula"
    description: str = """MongoDB'den belirtilen kritere göre kullanıcı sorgular veya tüm kullanıcıları listeler."""
    args_schema: Type[BaseModel] = MongoDBToolInput

    def _run(self, name: str = "all") -> str:
        # ... [Aynı MongoDB sorgu kodu buraya gelecek] ...
        return json.dumps(...)

    def _arun(self, name: str = "all"):
        raise NotImplementedError("Asenkron desteklenmiyor.")

tools = [MongoDBTool(), MerhabaTool(), tarih_ver]

# =========================
# ​​​ LangGraph – StateGraph + REACT Agent
# =========================

# Graph State yapısı
class State(TypedDict):
    messages: list[dict]  # Her mesaj bir dict olabilir

# 3a) StateGraph ile yapı kuruyoruz (isteğe bağlı)
graph_builder = StateGraph(State)
def append_user_and_ai(state):
    # tool çağrılıp agent çalıştırılacak yer
    return state

# 3b) En kolay yöntem: hazır REACT agent kullanmak
react_agent = create_react_agent(
    llm=llm,
    tools=tools,
    prompt=chat_prompt.system_messages[0].content,
)

compiled_graph = react_agent  # CompiledStateGraph

# =========================
# ​​​ Geçmiş Yükleme
# =========================
chat_history = []
for doc in chat_col.find().sort("timestamp", 1).limit(10):
    if doc["role"] == "human":
        chat_history.append({"role": "user", "content": doc["message"]})
    elif doc["role"] == "ai":
        chat_history.append({"role": "assistant", "content": doc["message"]})

print(f"💾 {len(chat_history)//2} önceki konuşma yüklendi.")

# =========================
# ​​​ Kullanıcı Döngüsü
# =========================
while True:
    prompt = input("\n🧠 Soru: ")
    if prompt.lower() in ["exit", "quit", "çıkış"]:
        print("Görüşmek üzere!")
        break

    # Gerekirse geçmiş + yeni mesajı hazırlayabilirsin
    inputs = {"messages": chat_history + [{"role": "user", "content": prompt}]}

    # Agent’i çalıştır
    for chunk in compiled_graph.stream(inputs, stream_mode="updates"):
        if "messages" in chunk:
            # Son mesajı al
            last = chunk["messages"][-1]
            output = last["content"]
            print(f"\n🤖 Cevap:\n{output}")

    # Geçmişi güncelle
    chat_history.append({"role": "user", "content": prompt})
    chat_history.append({"role": "assistant", "content": output})

    # MongoDB kaydı
    chat_col.insert_many([
        {"role": "human", "message": prompt, "timestamp": datetime.now()},
        {"role": "ai", "message": output, "timestamp": datetime.now()}
    ])
