#!/usr/bin/python3
# recap.py: a daily / weekly recap of your captured days, built deterministically from diary.json
# (the AI organizer's grouped output) plus the per-clip sidecars. No network and no model call here:
# the titles, summaries, topics, and action items were already produced by the organizer; this just
# WINDOWS them (today / last 7 days) and AGGREGATES them. Mirrors the iOS Recap: a stats bar
# (conversations, total time, words), the people and topics that came up, open action items, and the
# list of conversations in the window.
#
#   recap.py --rec-dir DIR [--period today|week|month|year]
#
# Output JSON: {ok, period, label, stats:{conversations,duration_min,words}, people[], topics[],
#               action_items[], days:[{date, heading, day_summary, conversations:[...]}]}
# Pure stdlib.
import sys, os, json, datetime

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
try:
    import meta as meta_store   # shared per-conversation overrides (hidden flag)
except Exception:
    meta_store = None

HOME = os.path.expanduser("~")
DEFAULT_REC = os.path.join(HOME, "Recordings/Epiphani")


def _conv_key(conv):
    """Stable conversation key = its first clip's filename (matches meta.py + the UI)."""
    clips = conv.get("clips") or []
    return clips[0].get("file", "") if clips else ""


def load_diary(rec_dir):
    try:
        with open(os.path.join(rec_dir, "diary.json"), encoding="utf-8") as f:
            return json.load(f)
    except (OSError, ValueError):
        return None


def _sidecar(rec_dir, fname):
    if not fname:
        return {}
    try:
        with open(os.path.join(rec_dir, ".organized", fname + ".json"), encoding="utf-8") as f:
            return json.load(f)
    except (OSError, ValueError):
        return {}


def _window_dates(period):
    """The set of YYYY-MM-DD day keys the recap covers. 'today' = the local date; the rolling windows
    cover the last N calendar days, today inclusive: week=7, month=30, year=365. Diary days are already
    date-bucketed, so a date match is enough. (Longer windows simply show everything that exists yet and
    grow richer the longer the app is used.)"""
    today = datetime.date.today()
    if period == "today":
        return {today.isoformat()}
    n = {"week": 7, "month": 30, "year": 365}.get(period, 7)
    return {(today - datetime.timedelta(days=i)).isoformat() for i in range(n)}


def build(rec_dir, period):
    diary = load_diary(rec_dir)
    if diary is None:
        return {"ok": False, "period": period,
                "error": "No diary yet. Record something and organize it first."}
    want = _window_dates(period)
    hidden = set(meta_store.hidden_keys(meta_store.load_meta(rec_dir))) if meta_store else set()
    days_out = []
    people, topics, actions, seen_actions = {}, {}, [], set()
    n_convs, total_sec, total_words = 0, 0, 0
    for day in diary.get("days", []):
        if day.get("date") not in want:
            continue
        day_convs = []
        for conv in day.get("conversations", []):
            if _conv_key(conv) in hidden:   # excluded by the user (meta.py); drop from the recap
                continue
            n_convs += 1
            who = (conv.get("who_with") or "").strip()
            if who:
                people[who] = people.get(who, 0) + 1
            for a in conv.get("action_items") or []:
                a = (a or "").strip()
                key = a.lower()
                if a and key not in seen_actions:
                    seen_actions.add(key)
                    actions.append(a)
            for clip in conv.get("clips") or []:
                sc = _sidecar(rec_dir, clip.get("file", ""))
                total_sec += sc.get("duration_sec") or 0
                total_words += len((sc.get("transcript") or "").split())
                for t in (sc.get("ai", {}).get("topics") or []):
                    t = (t or "").strip()
                    if t:
                        topics[t] = topics.get(t, 0) + 1
            day_convs.append({
                "title": conv.get("title", ""), "time_range": conv.get("time_range", ""),
                "who_with": who, "summary": conv.get("summary", ""),
                "category": conv.get("category", ""), "icon": conv.get("icon", ""),
                "when": "%s · %s" % (day.get("heading") or day.get("date", ""),
                                          conv.get("time_range", "")),
            })
        if day_convs:
            days_out.append({"date": day.get("date"), "heading": day.get("heading"),
                             "day_summary": day.get("day_summary", ""), "conversations": day_convs})

    def top(counts, n):
        return [k for k, _ in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))[:n]]

    return {
        "ok": True, "period": period,
        "label": {"today": "Today", "week": "Last 7 days", "month": "Last 30 days",
                  "year": "Last year"}.get(period, "Today"),
        "stats": {"conversations": n_convs, "duration_min": round(total_sec / 60.0),
                  "words": total_words},
        "people": top(people, 6), "topics": top(topics, 8),
        "action_items": actions, "days": days_out,
    }


def main(argv):
    rec_dir = os.path.expanduser(argv[argv.index("--rec-dir") + 1]) if "--rec-dir" in argv else DEFAULT_REC
    period = argv[argv.index("--period") + 1] if "--period" in argv else "today"
    if period not in ("today", "week", "month", "year"):
        period = "today"
    sys.stdout.write(json.dumps(build(rec_dir, period), ensure_ascii=False))


if __name__ == "__main__":
    main(sys.argv[1:])
