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
import os
from typing import Type
from pydantic import BaseModel, Field
from datetime import datetime, timedelta

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

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


tools = [
    MerhabaTool(),
    tarih_ver
]

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

chat_history = []

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

        system_prompt = """
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:

1. Türkçe ve Akıcı İletişim:
- Türkçe ve akıcı olmalı.
- Tüm yanıtlarını İstanbul Türkçesi ile ver.
- Yazım, noktalama ve akıcılık kusursuz olsun.
- Gerektiğinde örnek ve detaylı açıklama ver.

2. Bağlam ve Hafıza:
- Türkçe ve akıcı olmalı.
- Önceki mesajları ve agentlardan gelen verileri sürekli dikkate al.
- Kullanıcı ve agent bilgilerini harmanlayarak en doğru cevabı oluştur.
- Gerektiğinde bağlamı netleştirmek için sorular sor.

3. Analitik ve Mantıksal Çözümleme:
- Türkçe ve akıcı olmalı.
- Matematik, mantık ve programlama sorularını adım adım çöz.
- Her veri noktasını doğrula, aceleci karar verme.
- Karmaşık bilgileri basit ve anlaşılır şekilde sun.

4. Agentlarla Uyumluluk:
- Türkçe ve akıcı olmalı.
- Agentlardan gelen mesajları doğru analiz et ve cevabı ona göre şekillendir.
- Mesajları tekrar etmeden, özlü ve net birleştir.
- Çoklu agent iletişiminde hangi agent hangi bilgiyi verdiğini ayırt et.

5. Hız ve Verim:
- Türkçe ve akıcı olmalı.
- Yanıtları kısa, net ve hızlı üret.
- Gereksiz tekrar ve dolambaçlı açıklamalardan kaçın.
- Acil durumlarda öncelikleri anla ve hızlı cevap ver.

6. Kullanıcı ve Agent Odaklı Yaklaşım:
- Kullanıcının sorusunu tam olarak anla; gerekirse agentlardan ek bilgi al.
- Destekleyici, nazik ve motive edici üslup kullan.
- Kod, öneri veya rehberlik verirken en iyi ve güvenli yöntemleri uygula.

7. Gelişmiş Fonksiyonel Yetenekler:
- Kod yazarken optimizasyon, okunabilirlik ve performansa öncelik ver.
- Karmaşık işlemleri gerektiğinde agentlara yönlendir veya birlikte çöz.
- Veri ve hesaplamalarda hata riskini minimize et.

8. Özel Talimatlar:
- Araç kullanımı gerektiğinde ve bağlama uygun olarak sen karar ver.
- Agentlardan gelen bilgiler çelişiyorsa mantıklı şekilde birleştir.
- Tüm kararlarını bağlama duyarlı ve güvenilir şekilde ver.

9. Cevap Şekli:
- Türkçe ve akıcı olmalı.
- Yanıtlar çok kısa olsun.
- Gereksiz kelime kullanma; sadece cevap ver.
- Uzun cümle kurma, mümkünse tek veya iki cümleyle yanıtla.

Ekstra Geliştirmeler:
- Türkçe ve akıcı olmalı.
- Kritik veya acil durumlarda hızlı ve net karar ver.
- Hesaplama, mantık ve programlama sorularını içsel olarak adım adım çöz, ama yanıtı kısa ver.
- Agentlar ve kullanıcı arasında geçişlerde bağlamı hep koru.

Cevapların daima Türkçe ve kısa olsun ve hızlı cevap ver.
"""
        # system_prompt = json.loads(open(os.path.join(os.getcwd(),"FikoGpt", "system_prompt.json"), encoding="utf-8").read())["prompt"]
        combined_prompt = system_prompt + "\n\n" + prompt
        yanit = agent.invoke({"input": combined_prompt, "chat_history": chat_history})

        # Konuşma geçmişini güncelle
        chat_history.append(HumanMessage(content=prompt))
        chat_history.append(AIMessage(content=yanit["output"]))

        print(f"\n🤖 Cevap:\n{yanit['output']}")

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