import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")

"""
NewsAnalysis - Türkçe Duygu Analizi (Local / Offline)
=======================================================
Model  : kaixkhazaki/turkish-sentiment
         → dbmdz/bert-base-turkish-cased üzerine fine-tuned
         → Accuracy: %96.88 | F1 Macro: 0.9454
         → 490.000 örneklik veri setiyle eğitilmiş
DB     : SQL Server (pyodbc)

Kurulum (tek seferlik, ~2 GB):
    pip install transformers torch pyodbc

İlk çalıştırmada model otomatik indirilir (~430 MB).
Sonraki çalıştırmalarda cache'den yüklenir (internet gerekmez).
"""

import time
import pyodbc
from transformers import pipeline

# ──────────────────────────────────────────────
# AYARLAR
# ──────────────────────────────────────────────

# Projedeki bağlantı dizesiyle aynı sunucu/DB bilgisi
DB_CONNECTION = (
    "DRIVER={ODBC Driver 17 for SQL Server};"
    "SERVER=YOUR_SERVER_NAME;"
    "DATABASE=NewsAnalysis;"
    "Trusted_Connection=yes;"
    "TrustServerCertificate=yes;"
)

# En iyi Türkçe sentiment modeli
# Accuracy: %96.88 | F1: 0.9454 | Eğitim: 490k örnek
MODEL_ID = "kaixkhazaki/turkish-sentiment"

# Modelin ürettiği label'ları normalize et
LABEL_MAP = {
    "Positive": "positive",
    "Negative": "negative",
    "Notr":     "neutral",   # Bu model "Neutral" yerine "Notr" kullanıyor
    "Neutral":  "neutral",
}

# Kaç haberi aynı anda işleyeceğiz (batch)
# CPU için 8, GPU varsa 32-64 yapılabilir
BATCH_SIZE = 8
MAX_TEXT_LENGTH = 512


# ──────────────────────────────────────────────
# YARDIMCI FONKSİYONLAR
# ──────────────────────────────────────────────

def get_unanalyzed_news(cursor) -> list[dict]:
    """Henüz analiz edilmemiş haberleri (Sentiment IS NULL) çeker."""
    cursor.execute(
        "SELECT Id, Name, Description FROM News WHERE Sentiment IS NULL"
    )
    rows = cursor.fetchall()
    return [
        {"id": str(row[0]), "name": row[1] or "", "description": row[2] or ""}
        for row in rows
    ]


def save_batch(cursor, conn, batch_news: list[dict], batch_results: list):
    """Bir batch'in analiz sonuçlarını DB'ye kaydeder."""
    for news, result in zip(batch_news, batch_results):
        raw_label = result["label"]
        label     = LABEL_MAP.get(raw_label, raw_label.lower())
        score     = round(result["score"], 4)

        cursor.execute(
            "UPDATE News SET Sentiment = ?, SentimentScore = ? WHERE Id = ?",
            label, score, news["id"]
        )

        tag = {"positive": "[+]", "negative": "[-]", "neutral": "[=]"}.get(label, "[?]")
        print(f"  {tag} {label.upper()} ({score:.4f})  <- {news['name'][:55]}...")

    conn.commit()


# ──────────────────────────────────────────────
# ANA AKIŞ
# ──────────────────────────────────────────────

def main():
    print("[*] Model yukleniyor (ilk calistirmada indirme yapilir)...")
    classifier = pipeline(
        "text-classification",
        model=MODEL_ID,
        truncation=True,
        max_length=MAX_TEXT_LENGTH,
        device=-1   # -1 = CPU | GPU varsa: device=0
    )
    print(f"[OK] Model hazir: {MODEL_ID}\n")

    print("[DB] Veritabanina baglaniliyor...")
    conn   = pyodbc.connect(DB_CONNECTION)
    cursor = conn.cursor()

    news_list = get_unanalyzed_news(cursor)
    total = len(news_list)

    if total == 0:
        print("[OK] Analiz edilecek haber yok. Tum haberler zaten islenmis.")
        cursor.close()
        conn.close()
        return

    print(f"[>>] {total} haber analiz edilecek (batch_size={BATCH_SIZE}).\n")

    counts = {"positive": 0, "negative": 0, "neutral": 0, "error": 0}
    processed = 0

    # Batch batch işle
    for batch_start in range(0, total, BATCH_SIZE):
        batch_news = news_list[batch_start : batch_start + BATCH_SIZE]
        batch_num  = batch_start // BATCH_SIZE + 1
        batch_end  = min(batch_start + BATCH_SIZE, total)

        print(f"[Batch {batch_num}] Haberler {batch_start + 1}-{batch_end} / {total} isleniyor...")

        # Her haberin başlık + açıklama metnini birleştir
        texts = [
            f"{n['name']}. {n['description']}".strip()[:MAX_TEXT_LENGTH]
            for n in batch_news
        ]

        try:
            results = classifier(texts, batch_size=BATCH_SIZE)
            save_batch(cursor, conn, batch_news, results)

            for result in results:
                label = LABEL_MAP.get(result["label"], result["label"].lower())
                counts[label] = counts.get(label, 0) + 1

            processed += len(batch_news)

        except Exception as e:
            print(f"  [ERR] Batch hatasi: {e}")
            counts["error"] += len(batch_news)

        print()

    cursor.close()
    conn.close()

    print("-" * 45)
    print("OZET:")
    print(f"  [+] Olumlu  : {counts['positive']}")
    print(f"  [-] Olumsuz : {counts['negative']}")
    print(f"  [=] Notr    : {counts['neutral']}")
    print(f"  [!] Hata    : {counts['error']}")
    print(f"  [>] Toplam  : {processed}/{total}")
    print("-" * 45)
    print("[OK] Analiz tamamlandi!")


if __name__ == "__main__":
    main()
