"""İçerik üretici — DeepSeek V4 Flash (OpenAI uyumlu) + şablon yedeği.

build_context(): MatchEvent + Match -> yer tutucu sözlüğü
generate():      olaya göre tweet metni üretir (LLM veya şablon), 280 karaktere sığdırır.

Sistem promptu her istekte aynı tutulur (DeepSeek prompt cache = ~50x ucuz).
"""
import logging
from sqlalchemy.orm import Session

from app.db import models, crud
from app.content_engine import templates, textutil
import config

log = logging.getLogger("content")

MAX_LEN = 280

# olay tipi -> insan diliyle kısa açıklama (LLM'e bağlam)
EVENT_LABEL = {
    "goal": "gol",
    "goal_late": "son dakikalarda atılan gol (90+)",
    "penalty_goal": "penaltı golü",
    "own_goal": "kendi kalesine gol",
    "brace": "aynı oyuncunun maçtaki 2. golü",
    "hat_trick": "aynı oyuncunun hat-trick yapması (3 gol)",
    "yellow_card": "sarı kart",
    "second_yellow": "ikinci sarıdan kırmızı kart",
    "red_card": "kırmızı kart",
    "penalty_missed": "kaçan penaltı",
    "var": "VAR kararı",
    "injury": "sakatlık nedeniyle oyundan çıkma",
    "substitution": "oyuncu değişikliği",
    "kickoff": "maçın başlaması",
    "ht": "ilk yarının bitişi (devre arası)",
    "second_half": "ikinci yarının başlaması",
    "ft": "maçın bitişi (final skoru)",
    "comeback": "geriye düşüp skoru çevirme",
    "shootout": "penaltı atışlarına gidilmesi",
    "preview": "maç öncesi tanıtım (maç henüz başlamadı)",
    "lineup": "ilk 11'lerin açıklanması",
}

# lige göre hashtag (takım hashtag'i LLM'e bırakılır)
LEAGUE_TAG = {
    "super_lig": "#SüperLig",
    "trendyol_1lig": "#Trendyol1Lig",
    "ucl": "#ŞampiyonlarLigi",
    "uel": "#AvrupaLigi",
    "uecl": "#KonferansLigi",
    "premier_league": "#PremierLig",
    "la_liga": "#LaLiga",
    "serie_a": "#SerieA",
    "bundesliga": "#Bundesliga",
    "ligue_1": "#Ligue1",
}


def build_context(event: models.MatchEvent, match: models.Match) -> dict:
    hs = match.home_score if match.home_score is not None else 0
    as_ = match.away_score if match.away_score is not None else 0
    return {
        # Kurumsal ekler temizlenir: "GNK Dinamo Zagreb" -> "Dinamo Zagreb"
        "home": textutil.clean_team_name(match.home_team),
        "away": textutil.clean_team_name(match.away_team),
        "player": event.player or "",
        "minute": event.minute or "",
        "score": f"{hs}-{as_}",
        "detail": event.detail or "",
        "event_type": event.event_type,
    }


# ------------------------------------------------------------------ DeepSeek
_client = None
_client_key = None


def _get_client(api_key: str):
    global _client, _client_key
    if _client is not None and _client_key == api_key:
        return _client
    from openai import OpenAI
    _client = OpenAI(api_key=api_key, base_url=config.DEEPSEEK_BASE_URL)
    _client_key = api_key
    return _client


def _llm_prompt(ctx: dict, league_name: str, stats: dict | None = None,
                best: dict | None = None) -> str:
    label = EVENT_LABEL.get(ctx["event_type"], ctx["event_type"])
    lines = [
        f"Lig: {league_name}",
        f"Maç: {ctx['home']} - {ctx['away']}",
    ]
    # Maç öncesi içerikte (tanıtım, ilk 11) skor ANLAMSIZ — verilirse LLM
    # "Maç henüz başlamadı: 0-0" gibi saçma satırlar yazıyordu (17.08).
    if ctx["event_type"] not in ("preview", "lineup"):
        lines.append(f"Anlık skor: {ctx['score']}")
    lines.append(f"Olay: {label}")
    # Gerçek istatistik: "baskılıydı" uydurmasın diye SAYIYI veriyoruz.
    # Takım adları açıkça yazılır — "ev/deplasman" etiketi karıştırılabiliyor.
    if stats:
        lines.append("Maç istatistikleri:")
        for ad, (ev, dep) in stats.items():
            lines.append(f"  {ad} — {ctx['home']}: {ev} | {ctx['away']}: {dep}")
    if best:
        adlar = {"ev": ctx["home"], "deplasman": ctx["away"]}
        for taraf, (oyuncu, puan) in best.items():
            lines.append(f"{adlar.get(taraf, taraf)} en iyi oyuncu: "
                         f"{oyuncu} (reyting {puan})")
    if ctx["minute"]:
        lines.append(f"Dakika: {ctx['minute']}'")
    if ctx["player"]:
        lines.append(f"Oyuncu: {ctx['player']}")
    # Detay her olay tipinde geçirilir. Önceden yalnız birkaç tip listede
    # olduğu için maç öncesi tweeti başlama saatini SÖYLEYEMİYORDU.
    if ctx["detail"]:
        lines.append(f"Detay: {ctx['detail']}")
    task = (
        "Bu olay için tek bir Türkçe tweet yaz.\n\n"
        "EN ÖNEMLİ KURAL — UYDURMA YASAĞI: Yalnızca yukarıda VERİLEN "
        "bilgileri kullan. Yukarıda istatistik verilmişse onları kullanabilir "
        "ve yorumlayabilirsin (örn. topla oynama %66 ise 'oyunun kontrolü "
        "ev sahibindeydi' demek doğrudur). Ama VERİLMEYEN hiçbir şeyi "
        "yazma: sayı yoksa 'baskılıydı', 'nefes kesen mücadele', "
        "'taraftar coştu' gibi ifadeler UYDURMADIR. Görmediğin pozisyonu, "
        "hâkimiyeti, tepkiyi anlatma.\n"
        "ATIF KURALI: İstatistikler TAKIM geneline aittir; bunları tek bir "
        "oyuncuya yükleme. 'En iyi oyuncu' bilgisi ayrıdır — o oyuncunun "
        "takım istatistiğini (kurtarış, şut sayısı vb.) yaptığını YAZMA.\n\n"
        "Diğer kurallar: en fazla 220 karakter; doğal ve akıcı; olaya uygun "
        "1-2 emoji; abartma ve klişe yok; skoru VERİLEN değerle birebir yaz. "
        "İfadeni skora uydur: 'öne geçti' yalnız üstünlük el değiştirdiyse "
        "doğrudur; 3-0'da atılan gol 'farkı açtı'dır, 2-2'de 'eşitledi'dir.\n"
        "SATIR DÜZENİ: olayı ilk satıra yaz, skoru/bağlamı ALT SATIRA geçir "
        "(tek blok duvar metin yazma, en fazla 2 satır).\n"
        "Sadece tweet metnini döndür; tırnak, açıklama veya hashtag ekleme "
        "(etiketleri sistem kendisi ekler)."
    )
    return "\n".join(lines) + "\n\n" + task


# Bu olaylarda maçın gidişatı anlatılır — istatistik onlar için çekilir.
# Gol/kart gibi anlık olaylarda gereksiz (hem gecikme hem maliyet).
STATS_EVENTS = ("ht", "ft", "second_half", "comeback")


def _fetch_stats(match: models.Match, event_type: str) -> tuple[dict, dict]:
    """Gidişat anlatan olaylar için gerçek istatistikleri çeker."""
    if event_type not in STATS_EVENTS or not match.provider_match_id:
        return {}, {}
    try:
        from app.data_engine import sofascore as ss
        eid = int(match.provider_match_id)
        period = "1ST" if event_type == "ht" else "ALL"
        stats = ss.get_statistics(eid, period)
        best = ss.get_best_players(eid) if event_type == "ft" else {}
        return stats, best
    except Exception as e:
        log.warning("İstatistik alınamadı: %s", e)
        return {}, {}


def _generate_llm(db: Session, ctx: dict, league_name: str, api_key: str,
                  tone: str, stats: dict | None = None,
                  best: dict | None = None) -> str | None:
    try:
        client = _get_client(api_key)
        resp = client.chat.completions.create(
            model=config.DEEPSEEK_MODEL,
            messages=[
                {"role": "system", "content": tone},   # sabit -> cache'lenir
                {"role": "user", "content": _llm_prompt(ctx, league_name,
                                                        stats, best)},
            ],
            temperature=1.0,
            # DeepSeek V4 Flash içsel reasoning token harcar ve bunlar
            # max_tokens'a sayılır. Sınır bol tutulur (yalnız üretilen kadar
            # ödenir); 800'de yarım kalan metinler görülmüştü.
            max_tokens=10000,
        )
        choice = resp.choices[0]
        if choice.finish_reason == "length":
            # Yarım cümle yayınlamaktansa şablona düş
            crud.add_log(db, "LLM metni sınıra takıldı, şablona düşülüyor",
                         level="warn", source="content")
            return None
        text = (choice.message.content or "").strip().strip('"').strip()
        return text or None
    except Exception as e:
        crud.add_log(db, f"DeepSeek hatası, şablona düşülüyor: {e}",
                     level="warn", source="content")
        return None


# ------------------------------------------------------------------ birleşik
def _append_hashtag(text: str, league_key: str, match_tag: str = "") -> str:
    """Etiketleri boş satırdan sonra ekler: önce maç etiketi, sonra lig.

    Maç etiketi (#BJKvEYP) yayıncının o maç için kullandığı resmi etikettir;
    bizim tweetimizi o maçın konuşmasına bağlar, bu yüzden lig etiketinden
    önce gelir. İzlenen hesaplardan öğrenilir (bkz. x_engine/sources.py).
    """
    tags = [t for t in (match_tag, LEAGUE_TAG.get(league_key)) if t]
    return textutil.append_tags(text, tags, MAX_LEN)


def generate(db: Session, event: models.MatchEvent, match: models.Match) -> str:
    """Olay için tweet metni üretir. Her zaman bir metin döner (en kötü ihtimalle şablon)."""
    ctx = build_context(event, match)
    league = match.league
    league_key = league.key if league else ""
    league_name = league.name if league else ""

    engine = crud.get_setting(db, "content_engine", "deepseek")
    api_key = crud.get_setting(db, "deepseek_api_key", "")
    tone = crud.get_setting(db, "tone_prompt", "")

    text = None
    if engine == "deepseek" and api_key:
        stats, best = _fetch_stats(match, event.event_type)
        text = _generate_llm(db, ctx, league_name, api_key, tone, stats, best)

    if not text:
        text = templates.render(event.event_type, ctx)
    if not text:
        # bilinmeyen olay tipi için asgari metin
        text = f"{ctx['home']} {ctx['score']} {ctx['away']}"

    # Kaynak marka etiketleri (#beINSPORTS) bizim tweetimizde yer almaz
    blocked = _blocked_tags(db)
    text = textutil.strip_hashtags(text, blocked)
    text = textutil.normalize(text)
    text = _append_hashtag(text, league_key, match.hashtag or "")
    return textutil.fit(textutil.normalize(text), MAX_LEN)


def _blocked_tags(db: Session) -> set:
    handles = [h for (h,) in db.query(models.SourceAccount.handle).all()]
    return textutil.block_tags_from_sources(handles)
