#!/usr/bin/env python3
"""CebersPost smoke-проверки. Запускать в венве проекта из корня репозитория:
    ~/.venvs/cebers-post/bin/python cp_verify.py [--llm] [--e2e <rubric>]
--llm  — реальная генерация поста по рубрике (без отправки).
--e2e  — отправить ОДНУ карточку владельцу (реальный Telegram).
Тестовые черновики удаляются. Код возврата != 0 при провале.
"""
import asyncio
import os
import sqlite3
import sys
import time

import yaml

from cebers_post.config import settings
from cebers_post.storage import Storage
from cebers_post.drafter import Drafter
from cebers_post.collector import Collector
from cebers_post.ideas import (
    build_topic_instruction,
    _pick_myth_topic,
    _pick_fact_topic,
    adjust_rubric_by_feedback,
)
from cebers_post.images import (
    render_draft_image,
    render_post_image,
    resolve_brand,
    _flux_cooldown_path,
)

FAILS = []


def check(name, cond, detail=""):
    detail = str(detail) if detail else ""
    mark = "✅" if cond else "❌"
    print(f"{mark} {name}{(' — ' + detail) if detail else ''}")
    if not cond:
        FAILS.append(name)


def test_config(storage):
    print("\n== 1. Конфиг проектов ==")
    data = yaml.safe_load(open(os.path.join(os.getcwd(), "projects.yaml")))
    projects = Collector(storage)._load_projects()
    check("projects.yaml парсится", isinstance(data, dict) and "projects" in data)
    for p in projects:
        if getattr(p, "enabled", False) and getattr(p, "repo", None):
            check(f"repo существует: {p.name}", os.path.isdir(p.repo), p.repo)


def test_db(storage):
    print("\n== 2. БД ==")
    conn = sqlite3.connect(settings.database_path)
    n = conn.execute("SELECT COUNT(*) FROM drafts").fetchone()[0]
    by = dict(conn.execute("SELECT status, COUNT(*) FROM drafts GROUP BY status").fetchall())
    conn.close()
    check("БД открывается, есть черновики", n > 0, f"{n} шт, статусы={by}")


def test_dedup():
    print("\n== 3. Антидубль курируемых рубрик ==")
    for name, picker in (("миф", _pick_myth_topic), ("факт", _pick_fact_topic)):
        seeds, picked = [], []
        for _ in range(12):
            term, _g = picker(seeds)
            picked.append(term)
            seeds.insert(0, term)
        check(f"{name}: 12 подряд уникальны", len(set(picked)) == 12, f"{len(set(picked))}/12")
    instr, seed = build_topic_instruction("урок", ["Хук А"], ["Тема Б", "Тема В"], None)
    check("свободная рубрика мёржит hooks+seeds в бан", all(x in instr for x in ("Хук А", "Тема Б", "Тема В")) and seed is None)


def test_title_gate(storage):
    print("\n== 4. Гейт заголовков ==")
    g = Drafter(storage)._good_title
    cases = [
        ("t", "🧠 Знаете ли вы, что модели кешируют контекст? Ускоряет.", "fb"),
        ("А вы знали?", "Повторный запрос дешевле с кешем общей части промпта.", "fb"),
        ("🔮", "Миф: ИИ всегда прав. На деле он ошибается.", "fb"),
        ("Нормальный осмысленный заголовок", "тело", "fb"),
    ]
    for t, b, f in cases:
        out = g(t, b, f)
        ok = len(out) >= 8 and out.lower().rstrip("?!.…") not in {"а вы знали", "т", "миф", "факт"}
        check(f"title({t!r}) осмыслен", ok, repr(out))


def test_brand():
    print("\n== 5. Бренд по каналу ==")
    class D:
        def __init__(s, i, proj):
            s.id = i; s.title = "Тестовый заголовок поста"; s.image_headline = "Тестовый заголовок"
            s.rubric = "релиз"; s.track = "business"; s.project = proj; s.brand_key = None
    expect = {"идея": "kodoceh", "идея:@vakhunterInfo": "vakhunter", "VakHunter": "vakhunter"}
    for proj, key in expect.items():
        d = D(95000 + hash(proj) % 1000, proj)
        b = resolve_brand(d)
        check(f"resolve_brand({proj!r})={key}", b.key == key, b.key)
        p = render_draft_image(d, b)
        check(f"рендер {key} (вектор)", p.exists() and p.stat().st_size > 1000, p.name)
        try:
            p.unlink()
        except OSError:
            pass


async def test_flux_cooldown(storage):
    print("\n== 6. flux-cooldown ==")
    drafter = Drafter(storage)
    seeds = await asyncio.to_thread(storage.recent_idea_seeds, "факт", 30)
    topic, _ = build_topic_instruction("факт", [], seeds, None)
    d = await drafter.draft_idea(topic)
    _flux_cooldown_path().unlink(missing_ok=True)
    t = time.monotonic(); await render_post_image(storage.get_draft(d.draft_id)); dt1 = time.monotonic() - t
    cd = _flux_cooldown_path().exists()
    t = time.monotonic(); await render_post_image(storage.get_draft(d.draft_id)); dt2 = time.monotonic() - t
    if cd:
        check("flux недоступен → 2й рендер быстрый (cooldown)", dt2 < 5, f"1й={dt1:.1f}s 2й={dt2:.1f}s")
    else:
        check("flux доступен → AI-картинка отрисована", True, f"1й={dt1:.1f}s (cooldown не нужен)")
    conn = sqlite3.connect(settings.database_path)
    conn.execute("DELETE FROM drafts WHERE id=?", (d.draft_id,)); conn.commit(); conn.close()


async def main():
    argv = sys.argv[1:]
    storage = Storage(settings.database_path)
    test_config(storage)
    test_db(storage)
    test_dedup()
    test_title_gate(storage)
    test_brand()
    await test_flux_cooldown(storage)

    if "--llm" in argv:
        print("\n== 7. Реальная генерация (без отправки) ==")
        drafter = Drafter(storage)
        topic, _ = build_topic_instruction("инструмент", [], [], None)
        d = await drafter.draft_idea(topic)
        check("LLM вернул непустой пост", bool(d.title and d.body), d.title)
        conn = sqlite3.connect(settings.database_path)
        conn.execute("DELETE FROM drafts WHERE id=?", (d.draft_id,)); conn.commit(); conn.close()

    if "--e2e" in argv:
        from cebers_post.ideas import propose_idea
        rubric = argv[argv.index("--e2e") + 1] if len(argv) > argv.index("--e2e") + 1 else "факт"
        print(f"\n== 8. E2E отправка владельцу (rubric={rubric}) ==")
        await propose_idea(rubric)
        check("propose_idea отработал без исключений", True)

    print(f"\n{'='*40}\nИТОГ: {'ВСЁ ЗЕЛЁНОЕ' if not FAILS else 'ПРОВАЛЫ: ' + ', '.join(FAILS)}")
    sys.exit(1 if FAILS else 0)


if __name__ == "__main__":
    asyncio.run(main())
