import json
from datetime import datetime, timedelta
from typing import Any, Dict, List, Type

from langchain_community.llms import Ollama
from langchain.agents import initialize_agent, AgentType
from langchain.tools import BaseTool, tool
from pydantic import BaseModel, Field, ValidationError
from langchain.schema import HumanMessage, AIMessage

# 1️⃣ LLM Bağlantısı
llm = Ollama(model="llama3.1:latest")

# 2️⃣ Araçlar (JSON çıktılı)
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] # type: ignore

    def __init__(self):
        super().__init__()
        self.args_schema = HelloToolInput # type: ignore

    def _run(self, **kwargs) -> str:
        try:
            data = self.args_schema(**kwargs)
            return json.dumps({"cevap": f"Merhaba, {data.name}!"}, ensure_ascii=False) # type: ignore
        except ValidationError as e:
            return json.dumps({"hata": e.errors()}, ensure_ascii=False)

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

@tool
def tarih_ver(asd: Any = 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()
    dun = simdi - timedelta(days=1)
    yarin = simdi + timedelta(days=1)
    ertesi = simdi + timedelta(days=2)

    def gun_bilgisi(tarih: datetime) -> Dict[str, Any]:
        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: datetime) -> Dict[str, Any]:
        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)

tools = [MerhabaTool(), tarih_ver]

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

# 4️⃣ Multi-agent JSON mesajlaşma sistemi
chat_history_json: List[Dict[str, Any]] = []
agents = ["Agent1", "Agent2"]

def agent_mesaj_uret(agent_adi: str, mesaj: str) -> Dict[str, Any]:
    return {"agent": agent_adi, "mesaj": mesaj, "zaman": datetime.now().strftime("%H:%M:%S")}

while True:
    try:
        raw_input = input("\n🧠 Kullanıcı (JSON formatında): ")
        if raw_input.lower() in ["exit", "quit", "çıkış"]:
            print(json.dumps({"bilgi": "Görüşme sonlandırıldı."}, ensure_ascii=False))
            break

        try:
            user_input = json.loads(raw_input)
        except json.JSONDecodeError:
            print(json.dumps({"hata": "Geçersiz JSON formatı!"}, ensure_ascii=False))
            continue

        # Kullanıcı mesajını kaydet
        chat_history_json.append({"kullanici": user_input, "zaman": datetime.now().strftime("%H:%M:%S")})

        # Agentlar otomatik mesaj üretiyor
        for a in agents:
            mesaj = f"Merhaba, ben {a}. Kullanıcı: {user_input.get('soru','')}"
            chat_history_json.append(agent_mesaj_uret(a, mesaj))

        # Tüm geçmişi JSON olarak agenta gönder
        combined_prompt = json.dumps({
            "system": "FikoGPT: Tamamen Türkçe, bağlama duyarlı, hızlı ve yetenekli bir LLM.",
            "gecmis": chat_history_json
        }, ensure_ascii=False)

        yanit = agent.invoke({"input": combined_prompt, "chat_history": chat_history_json})

        # Yanıtı kaydet
        chat_history_json.append({"fikoGPT": {"cevap": yanit["output"]}, "zaman": datetime.now().strftime("%H:%M:%S")})

        print(json.dumps({"cevap": yanit["output"]}, ensure_ascii=False))

    except KeyboardInterrupt:
        print(json.dumps({"bilgi": "İşlem kesildi."}, ensure_ascii=False))
        break
    except Exception as e:
        print(json.dumps({"hata": str(e)}, ensure_ascii=False))
