"""Athena briefing engine — CyrilXBT masterclass format.

Generates structured morning intelligence briefings from PUBLISH/WATCH verdicts.

Output format:
    THE ONE THING
    WHAT HAPPENED
    WHAT TO WATCH
    FROM MEMORY
    TODAY'S FOCUS

Uses verdict + signal_score to rank, recency to gate age, and theme clustering
to avoid repetition from the same source within 72 hours.
"""
import sqlite3
from datetime import datetime, timedelta
from pathlib import Path


def _clean_summary(raw_summary) -> str:
    """Extract the one_liner from a JSON summary, or return raw text."""
    if not raw_summary:
        return "No summary available."
    try:
        import json as _json
        parsed = _json.loads(raw_summary) if isinstance(raw_summary, str) else raw_summary
        if isinstance(parsed, dict):
            return parsed.get("one_liner", raw_summary[:200])
    except Exception:
        pass
    return str(raw_summary)[:200]


def _item_summary(item) -> str:
    """Get a short readable summary for an item."""
    raw = item.get("summary")
    if not raw:
        return item.get("category_tags", "") or ""
    return _clean_summary(raw)


BRIEF_TEMPLATE = """# Morning Brief — {date}

## THE ONE THING

{one_thing}

## WHAT HAPPENED

{what_happened}

## WHAT TO WATCH

{what_to_watch}

## FROM MEMORY

{from_memory}

## TODAY'S FOCUS

{todays_focus}
"""


def get_connection(db_path: str) -> sqlite3.Connection:
    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row
    return conn


def _source_cooldown(conn: sqlite3.Connection, hours: int = 72) -> set:
    """Sources that have appeared in the last N hours — dedup rule.

    CyrilXBT rule: never repeat content from the same source within 72 hours.
    """
    cutoff = datetime.utcnow() - timedelta(hours=hours)
    cur = conn.execute(
        "SELECT DISTINCT source FROM entries WHERE first_seen >= ? AND verdict IN ('PUBLISH', 'WATCH')",
        (cutoff.isoformat(),),
    )
    return {row["source"] for row in cur}


def _theme_cooldown(conn: sqlite3.Connection, hours: int = 72) -> set:
    """Categories that have been heavily featured recently."""
    cutoff = datetime.utcnow() - timedelta(hours=hours)
    cur = conn.execute(
        "SELECT category_tags, COUNT(*) as c FROM entries "
        "WHERE first_seen >= ? AND verdict = 'PUBLISH' "
        "GROUP BY category_tags HAVING c >= 3",
        (cutoff.isoformat(),),
    )
    return {row["category_tags"] for row in cur}


def fetch_brief_items(
    conn: sqlite3.Connection,
    max_items: int = 8,
    max_age_h: float = 48,
    cooldown_h: int = 72,
) -> list:
    """Fetch brief-worthy items with dedup and cooldown applied."""
    cutoff = datetime.utcnow() - timedelta(hours=max_age_h)
    cooldown_sources = _source_cooldown(conn, cooldown_h)

    cur = conn.execute(
        """SELECT source, url, title, summary, signal_score, verdict,
                  source_tier, category_tags, first_seen
           FROM entries
           WHERE verdict IN ('PUBLISH', 'WATCH')
             AND first_seen >= ?
           ORDER BY signal_score DESC, first_seen DESC
           LIMIT ?""",
        (cutoff.isoformat(), max_items * 2),  # Oversample for filtering
    )

    items = []
    seen_sources = set()
    for row in cur:
        # Source dedup: max 2 per source in one brief
        if row["source"] in seen_sources and len([i for i in items if i["source"] == row["source"]]) >= 2:
            continue
        seen_sources.add(row["source"])
        items.append(dict(row))
        if len(items) >= max_items:
            break

    return items


def _cluster_themes(items: list) -> dict:
    """Group items by category_tags for structured output."""
    themes = {}
    for item in items:
        tag = item.get("category_tags") or "GENERAL"
        themes.setdefault(tag, []).append(item)
    return themes


def generate_brief(
    conn: sqlite3.Connection,
    max_items: int = 8,
    max_age_h: float = 48,
    output_path: str | None = None,
) -> dict:
    """Generate a complete briefing from Athena data.

    Returns dict with all sections populated.
    """
    items = fetch_brief_items(conn, max_items=max_items, max_age_h=max_age_h)
    if not items:
        return {"error": "No brief-worthy items in time window"}

    themes = _cluster_themes(items)

    # THE ONE THING — highest signal PUBLISH item
    top_item = items[0]
    one_thing = (
        f"**[{top_item['title']}]({top_item['url']})** "
        f"(Score: {top_item['signal_score']:.1f} | {top_item['source'].upper()})\n\n"
        + _clean_summary(top_item.get("summary"))
    )

    # WHAT HAPPENED — remaining items as bullet list
    happened_parts = []
    for item in items[1:]:
        tier_label = {1: "T1", 2: "T2", 3: "T3"}.get(item["source_tier"], "T?")
        happened_parts.append(
            f"- **[{item['title']}]({item['url']})** "
            f"[{tier_label}] — "
            + (_item_summary(item)[:200] if _item_summary(item) else f"{item.get('category_tags', '')}")
        )
    what_happened = "\n".join(happened_parts) if happened_parts else "_No additional items._"

    # WHAT TO WATCH — WATCH verdict items not yet in main list
    watch_items = [i for i in items if i["verdict"] == "WATCH"]
    if watch_items:
        watch_parts = []
        for item in watch_items[:3]:
            watch_parts.append(
                f"- [{item['title']}]({item['url']}) — "
                f"{item['category_tags']} (signal: {item['signal_score']:.1f})"
            )
        what_to_watch = "\n".join(watch_parts)
    else:
        what_to_watch = "_No developing stories in current window._"

    # FROM MEMORY — theme clusters with multiple items
    recurring = {k: v for k, v in themes.items() if len(v) >= 2}
    if recurring:
        memory_parts = []
        for theme, entries in recurring.items():
            sources = {e["source"] for e in entries}
            memory_parts.append(
                f"- **{theme}**: {len(entries)} items from {', '.join(sources)} — pattern detected"
            )
        from_memory = "\n".join(memory_parts)
    else:
        from_memory = "_No recurring patterns in this window._"

    # TODAY'S FOCUS — recommend based on highest-signal theme
    focus_theme = max(themes.items(), key=lambda x: len(x[1]))[0] if themes else "GENERAL"
    top_source = top_item["source"]
    todays_focus = (
        f"Focus on **{focus_theme}** developments — "
        f"highest signal item came from {top_source.upper()}. "
        f"Check for follow-ups and replication claims."
    )

    brief = {
        "date": datetime.utcnow().strftime("%Y-%m-%d"),
        "one_thing": one_thing,
        "what_happened": what_happened,
        "what_to_watch": what_to_watch,
        "from_memory": from_memory,
        "todays_focus": todays_focus,
        "items": items,
        "item_count": len(items),
    }

    # Render template
    brief["markdown"] = BRIEF_TEMPLATE.format(**brief)

    # Save if path provided
    if output_path:
        out = Path(output_path)
        out.parent.mkdir(parents=True, exist_ok=True)
        out.write_text(brief["markdown"], encoding="utf-8")
        brief["saved"] = str(out)

    return brief


def generate_brief_json(
    conn: sqlite3.Connection,
    max_items: int = 8,
    max_age_h: float = 48,
) -> dict:
    """Generate brief as JSON-serializable dict (for API/feed output)."""
    import json as _json

    brief = generate_brief(conn, max_items=max_items, max_age_h=max_age_h)
    brief["items_json"] = [
        {
            "title": i["title"],
            "url": i["url"],
            "source": i["source"],
            "signal_score": round(i["signal_score"], 2),
            "verdict": i["verdict"],
            "tier": i["source_tier"],
            "category": i.get("category_tags"),
        }
        for i in brief.get("items", [])
    ]
    return brief


# ── CLI ──

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="Generate Athena briefing")
    parser.add_argument("--db", default="oracle.db")
    parser.add_argument("--max-items", type=int, default=8)
    parser.add_argument("--max-age-h", type=float, default=48)
    parser.add_argument("--output", "-o", help="Output path for markdown brief")
    parser.add_argument("--json", action="store_true", help="Output as JSON")

    args = parser.parse_args()
    conn = get_connection(args.db)

    try:
        brief = generate_brief_json(conn, max_items=args.max_items, max_age_h=args.max_age_h)
        if args.json:
            import json
            print(json.dumps(brief, indent=2, default=str))
        elif args.output:
            generate_brief(conn, max_items=args.max_items, max_age_h=args.max_age_h, output_path=args.output)
            print(f"Saved: {args.output}")
        else:
            print(brief.get("markdown", brief.get("error", "No brief generated")))
    finally:
        conn.close()
