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

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">
"""

# 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="gpt-oss")

# 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("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.
    """
    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()

    # Günler
    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"),
        }

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

    # Geçen ay ve gelecek ay
    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)

    # Mevcut tüm bilgileri koruyarak yeni alanları ekliyoruz
    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)

# =========================
# 4️⃣ MongoDB Tool
# =========================
class MongoDBToolInput(BaseModel):
    name: str = Field(default="all", description="Bilgisi alınacak kullanıcının adı. 'all' veya boş ise tüm kullanıcılar listelenir.")

class MongoDBTool(BaseTool):
    name: str = "mongodb_kullanici_sorgula"
    description: str = "MongoDB'den belirtilen kullanıcı adını sorgular veya tüm kullanıcıları listeler."
    args_schema: Type[BaseModel] = MongoDBToolInput  # type: ignore

    def _run(self, name: str = "all") -> str:
        client = MongoClient("mongodb://fikoyt:fikoyt1299@fikoyt.com:9001/?replicaSet=rs0&tls=false&authSource=fikoyt")
        db = client["fikoyt"]
        collection = db["goUyeler"]

        if not name or name.lower() == "all"or name.lower() == "hepsi"or name.lower() == "tamamı":
            # Tüm kullanıcıları çek
            users = list(collection.find())
            client.close()
            if not users:
                return "Hiç kullanıcı bulunamadı."
            return json.dumps(users, ensure_ascii=False, default=json_util.default)
        else:
            # Belirli kullanıcıyı çek
            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 = "all"):
        raise NotImplementedError("Asenkron desteklenmiyor.")

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

# =========================
# 4️⃣ Agent Kurulumu
# =========================
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.CHAT_CONVERSATIONAL_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}")
