"""FastAPI uygulaması ve panel route'ları."""
from datetime import datetime, timedelta
from pathlib import Path

from fastapi import FastAPI, Request, Depends, Form
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from sqlalchemy import func
from sqlalchemy.orm import Session

import config
from app.db.database import init_db, get_session
from app.db import models, crud
from app.core import security, timeutil

BASE = Path(__file__).resolve().parent
templates = Jinja2Templates(directory=str(BASE / "web" / "templates"))
templates.env.filters["tr"] = timeutil.fmt_tr

app = FastAPI(title=config.APP_NAME, version=config.VERSION)
app.mount("/static", StaticFiles(directory=str(BASE / "web" / "static")), name="static")


@app.on_event("startup")
def _startup():
    init_db()
    from app.scheduler.manager import start_scheduler
    start_scheduler()


@app.on_event("shutdown")
def _shutdown():
    from app.scheduler.manager import shutdown_scheduler
    shutdown_scheduler()


def _nav(db: Session) -> dict:
    """Her sayfada kenar çubuğunda görünen canlı sayaçlar."""
    return {
        "live": db.query(models.Match).filter(
            models.Match.status.in_(["live", "ht"])).count(),
        "queue": db.query(models.Post).filter(
            models.Post.status.in_(["queued", "approved"])).count(),
        "posting": crud.get_setting(db, "posting_enabled", "false") == "true",
        "sources": db.query(models.SourceTweet).filter(
            models.SourceTweet.used == False).count(),  # noqa: E712
    }


def ctx(request: Request, db: Session = None, **extra):
    base = {
        "request": request, "app_name": config.APP_NAME, "version": config.VERSION,
        "nav": _nav(db) if db is not None else {"live": 0, "queue": 0, "posting": False},
    }
    base.update(extra)
    return base


def _today_start() -> datetime:
    return timeutil.tr_day_bounds_utc()[0]


# ================================================================== GENEL BAKIŞ
@app.get("/", response_class=HTMLResponse)
def dashboard(request: Request, db: Session = Depends(get_session)):
    from app.scheduler.manager import scheduler_running, job_status
    from app.scheduler import budget, coverage

    s = crud.all_settings(db)
    start = _today_start()

    posted_today = db.query(models.Post).filter(
        models.Post.status == "posted", models.Post.posted_at >= start).count()
    remaining, total, used = budget.remaining_budget(db)

    live = (db.query(models.Match)
            .filter(models.Match.status.in_(["live", "ht"]))
            .order_by(models.Match.kickoff).all())
    upcoming = (db.query(models.Match)
                .filter(models.Match.status == "scheduled",
                        models.Match.kickoff >= datetime.utcnow())
                .order_by(models.Match.kickoff).limit(5).all())

    # bugün gönderilenlerin tür dağılımı
    by_kind = (db.query(models.Post.kind, func.count(models.Post.id))
               .filter(models.Post.status == "posted", models.Post.posted_at >= start)
               .group_by(models.Post.kind)
               .order_by(func.count(models.Post.id).desc()).all())

    accounts = db.query(models.Account).all()
    checks = {
        "deepseek": bool(s.get("deepseek_api_key")),
        "accounts_ok": sum(1 for a in accounts if a.status == "ok" and a.is_active),
        "accounts_total": len(accounts),
        "posting": s.get("posting_enabled") == "true",
        "scheduler": scheduler_running(),
    }
    logs = db.query(models.LogEntry).order_by(models.LogEntry.id.desc()).limit(12).all()

    return templates.TemplateResponse("dashboard.html", ctx(
        request, db, active="dashboard", s=s, live=live, upcoming=upcoming,
        posted_today=posted_today, remaining=remaining, total=total, used=used,
        by_kind=by_kind, accounts=accounts, checks=checks, logs=logs,
        plan_info=budget.get_plan_info(db), jobs=job_status(),
        queue_count=db.query(models.Post).filter(
            models.Post.status.in_(["queued", "approved"])).count(),
        news_today=db.query(models.NewsItem).filter(
            models.NewsItem.created_at >= start).count(),
        coverage=coverage,
    ))


@app.post("/toggle-posting")
def toggle_posting(db: Session = Depends(get_session)):
    cur = crud.get_setting(db, "posting_enabled", "false")
    crud.set_setting(db, "posting_enabled", "false" if cur == "true" else "true")
    db.commit()
    crud.add_log(db, f"Ana paylaşım anahtarı: {'kapatıldı' if cur=='true' else 'açıldı'}",
                 source="panel")
    return RedirectResponse("/", status_code=303)


# ================================================================== MAÇLAR
@app.get("/matches", response_class=HTMLResponse)
def matches_page(request: Request, db: Session = Depends(get_session),
                 lig: str = "", durum: str = ""):
    from app.scheduler import coverage
    q = db.query(models.Match)
    if lig:
        q = q.join(models.League).filter(models.League.key == lig)
    if durum:
        if durum == "live":
            q = q.filter(models.Match.status.in_(["live", "ht"]))
        else:
            q = q.filter(models.Match.status == durum)

    live = (q.filter(models.Match.status.in_(["live", "ht"])).all()
            if not durum else [])
    now = datetime.utcnow()
    base = db.query(models.Match)
    if lig:
        base = base.join(models.League).filter(models.League.key == lig)

    upcoming = (base.filter(models.Match.status == "scheduled",
                            models.Match.kickoff >= now)
                .order_by(models.Match.kickoff).limit(40).all())
    recent = (base.filter(models.Match.status == "finished")
              .order_by(models.Match.kickoff.desc()).limit(25).all())
    if not live:
        live = (db.query(models.Match)
                .filter(models.Match.status.in_(["live", "ht"])).all())

    leagues = db.query(models.League).order_by(models.League.priority).all()
    tiers = {l.id: coverage.effective_tier(db, l) for l in leagues}
    return templates.TemplateResponse("matches.html", ctx(
        request, db, active="matches", live=live, upcoming=upcoming, recent=recent,
        leagues=leagues, lig=lig, tiers=tiers, labels=coverage.TIER_LABELS,
    ))


@app.get("/match/{match_id}", response_class=HTMLResponse)
def match_detail(match_id: int, request: Request, db: Session = Depends(get_session)):
    from app.scheduler import coverage
    m = db.get(models.Match, match_id)
    if not m:
        return RedirectResponse("/matches", status_code=303)
    events = (db.query(models.MatchEvent).filter_by(match_id=m.id)
              .order_by(models.MatchEvent.id).all())
    posts = (db.query(models.Post).filter_by(match_id=m.id)
             .order_by(models.Post.id).all())
    post_by_event = {p.event_id: p for p in posts if p.event_id}
    tier = coverage.effective_tier(db, m.league)
    allowed = coverage.TIERS[tier]
    account = db.query(models.Account).filter_by(status="ok").first()
    return templates.TemplateResponse("match_detail.html", ctx(
        request, db, active="matches", m=m, events=events, posts=posts,
        post_by_event=post_by_event, tier=tier, allowed=allowed,
        labels=coverage.TIER_LABELS, account=account,
    ))


# ================================================================== HABERLER
@app.get("/news", response_class=HTMLResponse)
def news_page(request: Request, db: Session = Depends(get_session), f: str = "ok"):
    from app.news_engine import rss, curator
    base = db.query(models.NewsItem)
    if f == "skip":
        rows = base.filter(models.NewsItem.skipped == True)  # noqa: E712
    elif f == "sent":
        rows = base.filter(models.NewsItem.tweeted == True)  # noqa: E712
    else:
        rows = base.filter(models.NewsItem.skipped == False)  # noqa: E712
    rows = rows.order_by(models.NewsItem.id.desc()).limit(60).all()

    fresh_cut = datetime.utcnow() - timedelta(minutes=curator.MAX_AGE_MINUTES)
    s = crud.all_settings(db)
    return templates.TemplateResponse("news.html", ctx(
        request, db, active="news", rows=rows, s=s, sources=rss.FEEDS, f=f,
        fresh_cut=fresh_cut, window=curator.MAX_AGE_MINUTES,
        counts={
            "ok": db.query(models.NewsItem).filter(
                models.NewsItem.skipped == False).count(),  # noqa: E712
            "skip": db.query(models.NewsItem).filter(
                models.NewsItem.skipped == True).count(),   # noqa: E712
            "sent": db.query(models.NewsItem).filter(
                models.NewsItem.tweeted == True).count(),   # noqa: E712
        },
    ))


@app.post("/news/refresh")
def news_refresh(db: Session = Depends(get_session)):
    from app.news_engine import curator
    stats = curator.ingest(db)
    crud.add_log(db, f"Manuel haber taraması: {stats}", source="news")
    return RedirectResponse("/news", status_code=303)


@app.post("/news/{item_id}/tweet")
def news_tweet(item_id: int, db: Session = Depends(get_session)):
    from app.news_engine import writer
    item = db.get(models.NewsItem, item_id)
    if item:
        text = writer.write_tweet(db, item)
        item.tweeted = True
        if text:
            db.add(models.Post(content=text, kind=item.category, status="queued"))
            crud.add_log(db, f"Haber kuyruğa alındı: {item.title[:60]}", source="news")
        else:
            item.skipped = True
            crud.add_log(db, f"Haber elendi: {item.title[:60]}",
                         level="warn", source="news")
        db.commit()
    return RedirectResponse("/news", status_code=303)


# ================================================================== KAYNAKLAR
@app.get("/sources", response_class=HTMLResponse)
def sources_page(request: Request, db: Session = Depends(get_session), f: str = "new"):
    q = db.query(models.SourceTweet)
    if f == "used":
        q = q.filter(models.SourceTweet.used == True)  # noqa: E712
    else:
        q = q.filter(models.SourceTweet.used == False)  # noqa: E712
    rows = q.order_by(models.SourceTweet.id.desc()).limit(60).all()
    accounts = db.query(models.SourceAccount).order_by(models.SourceAccount.id).all()
    s = crud.all_settings(db)
    from app.x_engine import importance, sources as src_mod
    now = datetime.utcnow()
    scores = {t.id: importance.total_score(t, now) for t in rows}
    why = {t.id: importance.explain(t, now) for t in rows}
    return templates.TemplateResponse("sources.html", ctx(
        request, db, active="sources", rows=rows, accounts=accounts, s=s, f=f,
        scores=scores, why=why, auto_kinds=src_mod.AUTO_KINDS,
        counts={
            "new": db.query(models.SourceTweet).filter(
                models.SourceTweet.used == False).count(),   # noqa: E712
            "used": db.query(models.SourceTweet).filter(
                models.SourceTweet.used == True).count(),    # noqa: E712
        },
    ))


@app.post("/sources/add")
def source_add(handle: str = Form(...), label: str = Form(""),
               db: Session = Depends(get_session)):
    h = handle.strip().lstrip("@")
    if h and not db.query(models.SourceAccount).filter_by(handle=h).first():
        db.add(models.SourceAccount(handle=h, label=label.strip() or h))
        db.commit()
        crud.add_log(db, f"Kaynak hesap eklendi: @{h}", source="sources")
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/{sid}/toggle")
def source_toggle(sid: int, db: Session = Depends(get_session)):
    s = db.get(models.SourceAccount, sid)
    if s:
        s.enabled = not s.enabled
        db.commit()
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/{sid}/auto")
def source_auto(sid: int, db: Session = Depends(get_session)):
    s = db.get(models.SourceAccount, sid)
    if s:
        s.auto_quote = not s.auto_quote
        db.commit()
        crud.add_log(db, f"@{s.handle} otomatik alıntı: "
                         f"{'açık' if s.auto_quote else 'kapalı'}", source="sources")
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/{sid}/delete")
def source_delete(sid: int, db: Session = Depends(get_session)):
    s = db.get(models.SourceAccount, sid)
    if s:
        db.query(models.SourceTweet).filter_by(source_id=s.id).delete()
        db.delete(s)
        db.commit()
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/refresh")
def sources_refresh(db: Session = Depends(get_session)):
    from app.x_engine import sources
    n = sources.poll_sources(db)
    crud.add_log(db, f"Manuel kaynak taraması: {n} yeni", source="sources")
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/tweet/{tid}/quote")
def source_quote(tid: int, db: Session = Depends(get_session)):
    """Bir kaynak tweeti alıntı olarak kuyruğa al (yorumu DeepSeek yazar)."""
    from app.content_engine import quote_writer
    item = db.get(models.SourceTweet, tid)
    if item:
        comment = quote_writer.write_comment(db, item)
        item.used = True
        text, media_url = ("", "")
        if comment:
            match = db.get(models.Match, item.match_id) if item.match_id else None
            text, media_url = quote_writer.build_tweet(comment, item, match)
        if text:
            db.add(models.Post(
                content=text, kind="quote", status="queued",
                match_id=item.match_id, media_source_url=media_url,
                is_reply=bool(match and match.thread_tweet_id)))
            crud.add_log(db, f"Kaynak paylaşımı kuyruğa alındı: @{item.handle}",
                         source="sources")
        else:
            item.skipped = True
        db.commit()
    return RedirectResponse("/sources", status_code=303)


@app.post("/sources/tweet/{tid}/skip")
def source_skip(tid: int, db: Session = Depends(get_session)):
    item = db.get(models.SourceTweet, tid)
    if item:
        item.used = True
        item.skipped = True
        db.commit()
    return RedirectResponse("/sources", status_code=303)


# ================================================================== KUYRUK
@app.get("/queue", response_class=HTMLResponse)
def queue_page(request: Request, db: Session = Depends(get_session), f: str = "pending"):
    if f == "history":
        rows = (db.query(models.Post)
                .filter(models.Post.status.in_(["posted", "failed", "cancelled"]))
                .order_by(models.Post.id.desc()).limit(80).all())
    else:
        rows = (db.query(models.Post)
                .filter(models.Post.status.in_(["queued", "approved"]))
                .order_by(models.Post.created_at.desc()).all())
    s = crud.all_settings(db)
    acc = db.query(models.Account).filter_by(status="ok").first()
    return templates.TemplateResponse("queue.html", ctx(
        request, db, active="queue", rows=rows, s=s, f=f, account=acc,
        counts={
            "pending": db.query(models.Post).filter(
                models.Post.status.in_(["queued", "approved"])).count(),
            "history": db.query(models.Post).filter(
                models.Post.status.in_(["posted", "failed", "cancelled"])).count(),
        },
    ))


@app.post("/queue/{post_id}/approve")
def queue_approve(post_id: int, db: Session = Depends(get_session)):
    p = db.get(models.Post, post_id)
    if p and p.status in ("queued", "approved"):
        p.status = "approved"
        db.commit()
    return RedirectResponse("/queue", status_code=303)


@app.post("/queue/{post_id}/cancel")
def queue_cancel(post_id: int, db: Session = Depends(get_session)):
    p = db.get(models.Post, post_id)
    if p:
        p.status = "cancelled"
        db.commit()
    return RedirectResponse("/queue", status_code=303)


@app.post("/queue/{post_id}/edit")
def queue_edit(post_id: int, content: str = Form(...), db: Session = Depends(get_session)):
    p = db.get(models.Post, post_id)
    if p and p.status in ("queued", "approved"):
        p.content = content[:280]
        db.commit()
    return RedirectResponse("/queue", status_code=303)


@app.post("/queue/{post_id}/send")
def queue_send_now(post_id: int, db: Session = Depends(get_session)):
    """Manuel anında gönder (ritim/aktif saat kuralını atlar)."""
    from app.x_engine import client as xclient
    p = db.get(models.Post, post_id)
    if not p or p.status not in ("queued", "approved"):
        return RedirectResponse("/queue", status_code=303)
    cap = int(crud.get_setting(db, "daily_post_cap", "120") or 120)
    acc = xclient.pick_account(db, cap)
    if not acc:
        crud.add_log(db, "Manuel gönderim: uygun hesap yok", level="warn", source="panel")
        return RedirectResponse("/queue?err=noacc", status_code=303)
    match = db.get(models.Match, p.match_id) if p.match_id else None
    reply_to = match.last_tweet_id if (match and p.is_reply and match.last_tweet_id) else None
    tid = xclient.post_tweet(db, acc, p.content, reply_to=reply_to,
                             media_url=p.media_source_url or None)
    if tid == "unknown":
        # X sessizce reddetmiş olabilir — başarı sayma, kuyrukta bırak
        crud.add_log(db, "X boş yanıt döndürdü, tweet kuyrukta bırakıldı",
                     level="warn", source="panel")
        return RedirectResponse("/queue?err=empty", status_code=303)
    if tid and tid != "duplicate":
        p.status = "posted"
        p.account_id = acc.id
        p.tweet_id = tid
        p.posted_at = datetime.utcnow()
        if match and tid != "unknown":
            if not match.thread_tweet_id:
                match.thread_tweet_id = tid
            match.last_tweet_id = tid
        db.commit()
    return RedirectResponse("/queue", status_code=303)


@app.post("/queue/manual")
def queue_manual(content: str = Form(...), db: Session = Depends(get_session)):
    if content.strip():
        db.add(models.Post(content=content.strip()[:280], kind="manual", status="approved"))
        db.commit()
        crud.add_log(db, "Manuel tweet kuyruğa eklendi", source="panel")
    return RedirectResponse("/queue", status_code=303)


# ================================================================== ŞABLONLAR
@app.get("/templates", response_class=HTMLResponse)
def templates_page(request: Request, db: Session = Depends(get_session)):
    from app.content_engine import templates as tpl
    from app.content_engine.generator import EVENT_LABEL
    groups = []
    for key, pool in tpl.BY_TYPE.items():
        groups.append({
            "key": key,
            "label": EVENT_LABEL.get(key, key),
            # NOT: "items" adını KULLANMA — Jinja'da g.items sözlüğün
            # .items() metoduna çözülür, listeye değil.
            "variants": pool,
        })
    groups.sort(key=lambda g: -len(g["variants"]))
    return templates.TemplateResponse("templates.html", ctx(
        request, db, active="templates", groups=groups,
        total=tpl.template_count(),
    ))


# ================================================================== LİGLER
@app.get("/leagues", response_class=HTMLResponse)
def leagues_page(request: Request, db: Session = Depends(get_session)):
    from app.scheduler import coverage, budget
    leagues = db.query(models.League).order_by(
        models.League.priority, models.League.name).all()
    tiers = [(k, coverage.TIER_LABELS[k]) for k in
             ("auto", "full", "standard", "minimal", "result_only")]
    setting = {l.id: coverage.tier_for_league(l) for l in leagues}
    effective = {l.id: coverage.effective_tier(db, l) for l in leagues}
    counts = dict(
        db.query(models.League.id, func.count(models.Match.id))
        .outerjoin(models.Match, models.Match.league_id == models.League.id)
        .group_by(models.League.id).all()
    )
    return templates.TemplateResponse("leagues.html", ctx(
        request, db, active="leagues", leagues=leagues, tiers=tiers,
        setting=setting, effective=effective, labels=coverage.TIER_LABELS,
        counts=counts, TIERS=coverage.TIERS, cost=budget.TIER_COST,
    ))


@app.post("/leagues/{lg_id}/toggle")
def league_toggle(lg_id: int, db: Session = Depends(get_session)):
    lg = db.get(models.League, lg_id)
    if lg:
        lg.enabled = not lg.enabled
        db.commit()
    return RedirectResponse("/leagues", status_code=303)


@app.post("/leagues/{lg_id}/coverage")
def league_coverage(lg_id: int, coverage_level: str = Form(...),
                    db: Session = Depends(get_session)):
    from app.scheduler import coverage as cov
    lg = db.get(models.League, lg_id)
    if lg and coverage_level in ("auto", *cov.TIERS.keys()):
        lg.coverage = coverage_level
        db.commit()
    return RedirectResponse("/leagues", status_code=303)


# ================================================================== BÜTÇE
@app.get("/budget", response_class=HTMLResponse)
def budget_page(request: Request, db: Session = Depends(get_session)):
    from app.scheduler import budget, coverage
    info = budget.get_plan_info(db)
    plan = budget.get_plan(db)
    remaining, total, used = budget.remaining_budget(db)
    leagues = db.query(models.League).filter_by(enabled=True).order_by(
        models.League.priority).all()
    todays = budget._todays_matches(db)
    per_league = {}
    for m in todays:
        per_league[m.league_id] = per_league.get(m.league_id, 0) + 1
    s = crud.all_settings(db)
    return templates.TemplateResponse("budget.html", ctx(
        request, db, active="budget", info=info, plan=plan, leagues=leagues,
        per_league=per_league, remaining=remaining, total=total, used=used,
        cost=budget.TIER_COST, coverage=coverage, s=s,
        reserve=budget.NON_MATCH_RESERVE,
    ))


@app.post("/budget/recalc")
def budget_recalc(db: Session = Depends(get_session)):
    from app.scheduler import budget
    budget.plan(db)
    return RedirectResponse("/budget", status_code=303)


@app.post("/budget/toggle")
def budget_toggle(db: Session = Depends(get_session)):
    cur = crud.get_setting(db, "budget_enabled", "true")
    crud.set_setting(db, "budget_enabled", "false" if cur == "true" else "true")
    db.commit()
    return RedirectResponse("/budget", status_code=303)


# ================================================================== HESAPLAR
@app.get("/accounts", response_class=HTMLResponse)
def accounts_page(request: Request, db: Session = Depends(get_session)):
    from app.x_engine.client import todays_post_count
    accounts = db.query(models.Account).order_by(models.Account.id).all()
    cap = int(crud.get_setting(db, "daily_post_cap", "120") or 120)
    usage = {a.id: todays_post_count(db, a.id) for a in accounts}
    return templates.TemplateResponse("accounts.html", ctx(
        request, db, active="accounts", accounts=accounts, usage=usage, cap=cap,
    ))


@app.post("/accounts/add")
def account_add(db: Session = Depends(get_session), label: str = Form(...),
                username: str = Form(""), auth_token: str = Form(...),
                ct0: str = Form(...), notes: str = Form("")):
    crud.create_account(db, label, username, auth_token, ct0, notes)
    crud.add_log(db, f"Hesap eklendi: {label}", source="panel")
    return RedirectResponse("/accounts", status_code=303)


@app.post("/accounts/{acc_id}/verify")
def account_verify(acc_id: int, db: Session = Depends(get_session)):
    from app.x_engine import client as xclient
    acc = db.get(models.Account, acc_id)
    if acc:
        xclient.verify_account(db, acc)
    return RedirectResponse("/accounts", status_code=303)


@app.post("/accounts/{acc_id}/toggle")
def account_toggle(acc_id: int, db: Session = Depends(get_session)):
    acc = db.get(models.Account, acc_id)
    if acc:
        acc.is_active = not acc.is_active
        db.commit()
    return RedirectResponse("/accounts", status_code=303)


@app.post("/accounts/{acc_id}/delete")
def account_delete(acc_id: int, db: Session = Depends(get_session)):
    acc = db.get(models.Account, acc_id)
    if acc:
        db.delete(acc)
        db.commit()
        crud.add_log(db, f"Hesap silindi: {acc.label}", source="panel")
    return RedirectResponse("/accounts", status_code=303)


# ================================================================== İŞLER
@app.get("/jobs", response_class=HTMLResponse)
def jobs_page(request: Request, db: Session = Depends(get_session)):
    from app.scheduler.manager import job_status, scheduler_running, JOB_INFO
    return templates.TemplateResponse("jobs.html", ctx(
        request, db, active="jobs", jobs=job_status(),
        running=scheduler_running(), info=JOB_INFO,
    ))


@app.post("/jobs/{job_id}/run")
def job_run_now(job_id: str, db: Session = Depends(get_session)):
    from app.scheduler.manager import run_job_now
    ok = run_job_now(job_id)
    crud.add_log(db, f"İş elle çalıştırıldı: {job_id}" if ok
                 else f"İş bulunamadı: {job_id}",
                 level="info" if ok else "warn", source="panel")
    return RedirectResponse("/jobs", status_code=303)


# ================================================================== AYARLAR
@app.get("/settings", response_class=HTMLResponse)
def settings_page(request: Request, db: Session = Depends(get_session)):
    s = crud.all_settings(db)
    key = s.get("deepseek_api_key", "")
    return templates.TemplateResponse("settings.html", ctx(
        request, db, active="settings", s=s,
        deepseek_masked=security.mask(key), has_key=bool(key),
    ))


@app.post("/settings")
def settings_save(
    db: Session = Depends(get_session),
    automation_mode: str = Form("auto"),
    posting_enabled: str = Form("false"),
    content_engine: str = Form("deepseek"),
    deepseek_api_key: str = Form(""),
    tone_prompt: str = Form(""),
    news_enabled: str = Form("true"),
    news_per_hour: str = Form("2"),
    budget_enabled: str = Form("true"),
    sources_enabled: str = Form("true"),
    quotes_per_hour: str = Form("3"),
    images_enabled: str = Form("true"),
    images_per_day: str = Form("20"),
    wiro_api_key: str = Form(""),
    active_hours_start: str = Form("8"),
    active_hours_end: str = Form("24"),
    min_gap_seconds: str = Form("90"),
    max_gap_seconds: str = Form("400"),
    reply_min_gap_seconds: str = Form("15"),
    reply_max_gap_seconds: str = Form("45"),
    daily_post_cap: str = Form("120"),
):
    pairs = [
        ("automation_mode", automation_mode),
        ("posting_enabled", "true" if posting_enabled == "true" else "false"),
        ("content_engine", content_engine),
        ("tone_prompt", tone_prompt),
        ("news_enabled", "true" if news_enabled == "true" else "false"),
        ("news_per_hour", news_per_hour),
        ("budget_enabled", "true" if budget_enabled == "true" else "false"),
        ("sources_enabled", "true" if sources_enabled == "true" else "false"),
        ("quotes_per_hour", quotes_per_hour),
        ("images_enabled", "true" if images_enabled == "true" else "false"),
        ("images_per_day", images_per_day),
        ("active_hours_start", active_hours_start),
        ("active_hours_end", active_hours_end),
        ("min_gap_seconds", min_gap_seconds),
        ("max_gap_seconds", max_gap_seconds),
        ("reply_min_gap_seconds", reply_min_gap_seconds),
        ("reply_max_gap_seconds", reply_max_gap_seconds),
        ("daily_post_cap", daily_post_cap),
    ]
    for k, v in pairs:
        crud.set_setting(db, k, v)
    if deepseek_api_key.strip():
        crud.set_setting(db, "deepseek_api_key", deepseek_api_key.strip(), is_secret=True)
    if wiro_api_key.strip():
        crud.set_setting(db, "wiro_api_key", wiro_api_key.strip(), is_secret=True)
    db.commit()
    crud.add_log(db, "Ayarlar güncellendi", source="panel")
    return RedirectResponse("/settings?saved=1", status_code=303)


# ================================================================== İSTATİSTİK
@app.get("/stats", response_class=HTMLResponse)
def stats_page(request: Request, db: Session = Depends(get_session)):
    now = datetime.utcnow()
    week_ago = now - timedelta(days=7)

    daily = (db.query(func.date(models.Post.posted_at), func.count(models.Post.id))
             .filter(models.Post.status == "posted", models.Post.posted_at >= week_ago)
             .group_by(func.date(models.Post.posted_at))
             .order_by(func.date(models.Post.posted_at)).all())
    by_kind = (db.query(models.Post.kind, func.count(models.Post.id))
               .filter(models.Post.status == "posted")
               .group_by(models.Post.kind)
               .order_by(func.count(models.Post.id).desc()).all())
    by_status = (db.query(models.Post.status, func.count(models.Post.id))
                 .group_by(models.Post.status).all())
    by_league = (db.query(models.League.name, func.count(models.Post.id))
                 .join(models.Match, models.Match.league_id == models.League.id)
                 .join(models.Post, models.Post.match_id == models.Match.id)
                 .filter(models.Post.status == "posted")
                 .group_by(models.League.name)
                 .order_by(func.count(models.Post.id).desc()).all())
    by_account = (db.query(models.Account.label, func.count(models.Post.id))
                  .join(models.Post, models.Post.account_id == models.Account.id)
                  .filter(models.Post.status == "posted")
                  .group_by(models.Account.label).all())
    news_sources = (db.query(models.NewsItem.source, func.count(models.NewsItem.id))
                    .group_by(models.NewsItem.source)
                    .order_by(func.count(models.NewsItem.id).desc()).all())
    totals = {
        "posted": db.query(models.Post).filter_by(status="posted").count(),
        "matches": db.query(models.Match).count(),
        "events": db.query(models.MatchEvent).count(),
        "news": db.query(models.NewsItem).count(),
    }
    return templates.TemplateResponse("stats.html", ctx(
        request, db, active="stats", daily=daily, by_kind=by_kind,
        by_status=by_status, by_league=by_league, by_account=by_account,
        news_sources=news_sources, totals=totals,
    ))


# ================================================================== LOGLAR
@app.get("/logs", response_class=HTMLResponse)
def logs_page(request: Request, db: Session = Depends(get_session),
              level: str = "", source: str = "", q: str = ""):
    rows = db.query(models.LogEntry)
    if level:
        rows = rows.filter(models.LogEntry.level == level)
    if source:
        rows = rows.filter(models.LogEntry.source == source)
    if q:
        rows = rows.filter(models.LogEntry.message.like(f"%{q}%"))
    rows = rows.order_by(models.LogEntry.id.desc()).limit(250).all()
    sources = [r[0] for r in db.query(models.LogEntry.source).distinct().all() if r[0]]
    counts = dict(
        db.query(models.LogEntry.level, func.count(models.LogEntry.id))
        .group_by(models.LogEntry.level).all()
    )
    return templates.TemplateResponse("logs.html", ctx(
        request, db, active="logs", rows=rows, sources=sorted(sources),
        level=level, source=source, q=q, counts=counts,
    ))


@app.get("/health")
def health():
    return {"ok": True, "version": config.VERSION}
