import json
from langchain_community.llms import Ollama
from langchain.agents import initialize_agent, AgentType
from langchain.tools import BaseTool, tool
from langchain.schema import HumanMessage, AIMessage, SystemMessage
from langchain.prompts.chat import ChatPromptTemplate
import os
from typing import Type
from pydantic import BaseModel, Field
from datetime import datetime, timedelta
from bson import json_util
from pymongo import MongoClient

# =========================
# 1️⃣ 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
"""

# Prompt template ile system message oluştur
chat_prompt = ChatPromptTemplate.from_messages([
    SystemMessage(content=system_prompt_text),
    HumanMessage(content="{user_input}")  # Kullanıcı mesajı burada geçecek
])

# Ollama LLM
llm = Ollama(model="llama3.1:latest", temperature=0, top_p=0, top_k=0)

# =========================
# 2️⃣ 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  # type: ignore

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

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

@tool
def tarih_ver(asd=None) -> str:
    ay_adlari = {1:"Ocak",2:"Şubat",3:"Mart",4:"Nisan",5:"Mayıs",6:"Haziran",
                 7:"Temmuz",8:"Ağustos",9:"Eylül",10:"Ekim",11:"Kasım",12:"Aralık"}
    gun_adlari = {0:"Pazartesi",1:"Salı",2:"Çarşamba",3:"Perşembe",4:"Cuma",5:"Cumartesi",6:"Pazar"}
    simdi = datetime.now()
    dun = simdi - timedelta(days=1)
    yarin = simdi + timedelta(days=1)
    ertesi = simdi + timedelta(days=2)

    def gun_bilgisi(tarih):
        return {"tarih": tarih.strftime("%d.%m.%Y %H:%M:%S"),"gun": gun_adlari[tarih.weekday()],
                "ay": ay_adlari[tarih.month],"ay_sayisi": tarih.month,"yil": tarih.year,
                "saat": tarih.hour,"dakika": tarih.minute,"saniye": tarih.second,
                "tam_kisa_saat": tarih.strftime("%H:%M"),"tam_uzun_saat": tarih.strftime("%H:%M:%S"),
                "tam_kisa_tarih": tarih.strftime("%d.%m.%Y"),
                "tam_uzun_tarih": tarih.strftime("%d.%m.%Y %H:%M:%S"),
                "hafta": int(tarih.strftime("%W")) + 1,"haftanin_gunu": tarih.strftime("%w")}

    def ay_bilgisi(tarih):
        return {"ay": ay_adlari[tarih.month],"yil": tarih.year,"ay_sayisi": tarih.month}

    gecenay = datetime(simdi.year if simdi.month>1 else simdi.year-1,
                       simdi.month-1 if simdi.month>1 else 12, 1)
    gelecekay = datetime(simdi.year if simdi.month<12 else simdi.year+1,
                         simdi.month+1 if simdi.month<12 else 1, 1)

    sonuc = gun_bilgisi(simdi)
    sonuc.update({"dun": gun_bilgisi(dun),"yarin": gun_bilgisi(yarin),
                  "ertesi": gun_bilgisi(ertesi),
                  "gecen_ay": ay_bilgisi(gecenay),"bu_ay": ay_bilgisi(simdi),
                  "gelecek_ay": ay_bilgisi(gelecekay)})
    return json.dumps(sonuc, ensure_ascii=False)

# =========================
# 3️⃣ MongoDB Tool
# =========================
class MongoDBToolInput(BaseModel):
    name: str = Field(description="Bilgisi alınacak kullanıcının adı")

class MongoDBTool(BaseTool):
    name = "mongodb_kullanici_sorgula"
    description = "MongoDB'den belirtilen kullanıcı adını sorgular."
    args_schema = MongoDBToolInput

    def _run(self, name: str) -> str:
        client = MongoClient("mongodb://fikoyt:fikoyt1299@fikoyt.com:9001/?replicaSet=rs0&tls=false&authSource=fikoyt")
        db = client["fikoyt"]
        collection = db["goUyeler"]
        user = collection.find_one({"isim": name})
        client.close()
        if not user:
            return f"{name} isimli kullanıcı bulunamadı."
        return json.dumps(user, ensure_ascii=False, default=json_util.default)

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

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

# =========================
# 4️⃣ Agent Kurulumu
# =========================
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    max_iterations=5,
    verbose=True,
    handle_parsing_errors=True
)

# =========================
# 5️⃣ Kullanıcı Döngüsü
# =========================
chat_history = []

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

        # System prompt + kullanıcı mesajını birleştir
        prompt_messages = chat_prompt.format_prompt(user_input=prompt).to_messages()

        # LLM + Agent ile çalıştır
        yanit_text = agent.run(input=prompt, chat_history=chat_history)

        # Konuşma geçmişi güncelle
        chat_history.append(HumanMessage(content=prompt))
        chat_history.append(AIMessage(content=yanit_text))

        print(f"\n🤖 Cevap:\n{yanit_text}")

    except KeyboardInterrupt:
        print("\nİşlem kesildi.")
        break
    except Exception as e:
        print(f"Genel bir hata oluştu: {e}")
