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
from pydantic import BaseModel, Field
from datetime import datetime, timedelta
from bson import json_util
from pymongo import MongoClient
from typing import Type

# =========================
# 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
# =========================
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.
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
# =========================
llm = Ollama(model="gpt-oss")

# =========================
# 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()

@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],
            "yil": tarih.year,
            "hafta": int(tarih.strftime("%W")) + 1
        }

    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": ay_adlari[gecenay.month], "yil": gecenay.year},
        "bu_ay": {"ay": ay_adlari[simdi.month], "yil": simdi.year},
        "gelecek_ay": {"ay": ay_adlari[gelecekay.month], "yil": gelecekay.year}
    })
    return json.dumps(sonuc, ensure_ascii=False)

class MongoDBToolInput(BaseModel):
    name: str = Field(default="all", description="Kullanıcı adı")

class MongoDBTool(BaseTool):
    name: str = "mongodb_kullanici_sorgula"
    description: str = "MongoDB'den belirtilen kullanıcıyı sorgular."
    args_schema: Type[BaseModel] = MongoDBToolInput # type: ignore

    def _run(self, name: str = "all") -> str:
        collection = db[COLLECTION_USERS]
        if name.lower() in ["all", "hepsi", "tamamı"]:
            users = list(collection.find())
            return json.dumps(users, ensure_ascii=False, default=json_util.default)
        else:
            user = collection.find_one({"isim": name})
            return json.dumps(user, ensure_ascii=False, default=json_util.default) if user else "Kullanıcı bulunamadı."

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

# =========================
# Agent
# =========================
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
    max_iterations=5,
    verbose=True,
    handle_parsing_errors=True
)

# =========================
# Geçmişi Yükleme
# =========================
chat_history = []
for doc in chat_col.find().sort("timestamp", 1):
    if doc["role"] == "human":
        chat_history.append(HumanMessage(content=doc["message"]))
    elif doc["role"] == "ai":
        chat_history.append(AIMessage(content=doc["message"]))

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

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

        prompt_messages = chat_prompt.format_prompt(user_input=prompt).to_messages()

        yanit_text = agent.run(input=prompt, chat_history=chat_history)

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

        # MongoDB'ye kaydet
        chat_col.insert_many([
            {"role": "human", "message": prompt, "timestamp": datetime.utcnow()},
            {"role": "ai", "message": yanit_text, "timestamp": datetime.utcnow()}
        ])

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

    except KeyboardInterrupt:
        print("\nİşlem kesildi.")
        break
    except Exception as e:
        print(f"Hata: {e}")
