#!/usr/bin/env python3
"""
Attention-digest state (off-repo, leaf module)
==============================================
Idempotency + cadence for the automatic email->todo engine (`attention_digest.py`).
Keeps two things so a re-run never re-creates the same todos:

  * ``processed_ids`` — Message-IDs of inbound mail already scanned (a rolling, capped
    list). The engine skips any message already here, so an overlapping daily lookback
    window (e.g. 48h scanned once/day) never double-files a commitment.
  * ``last_run_date`` — the local date the engine last completed a pass, so a caller that
    doesn't own its own cadence (the laptop 3-hourly inbox poll) still runs the digest
    at most once per day.

Deliberately mirrors ``team_state.py``: an off-repo JSON store (``~/.alexandria`` by
default, override with ``ALEXANDRIA_STATE_DIR``) that must never sync to the vault repo,
plus a human-readable JSONL audit trail. All writes are best-effort — a missing or
unwritable store degrades to "scan everything again" rather than breaking a run. No
dependencies of its own, so the engine can import it without a cycle.
"""
import os
import json
from pathlib import Path


def _state_dir():
    d = os.environ.get("ALEXANDRIA_STATE_DIR")
    return Path(d).expanduser() if d else (Path.home() / ".alexandria")


STATE_PATH = Path(os.environ.get(
    "ATTENTION_DIGEST_STATE", str(_state_dir() / "attention-state.json")))
AUDIT_PATH = Path(os.environ.get(
    "ATTENTION_DIGEST_AUDIT", str(_state_dir() / "attention-audit.jsonl")))
_KEEP_IDS = 1000   # cap the rolling id list so the state file can't grow without bound


def load():
    try:
        return json.loads(STATE_PATH.read_text())
    except Exception:
        return {}


def save(state):
    try:
        STATE_PATH.parent.mkdir(parents=True, exist_ok=True)
        STATE_PATH.write_text(json.dumps(state, indent=2))
    except Exception:
        pass


def _push(seq, value):
    seq = [x for x in (seq or []) if x != value]
    seq.append(value)
    return seq[-_KEEP_IDS:]


def is_processed(msg_id):
    return bool(msg_id) and msg_id in set(load().get("processed_ids", []))


def mark_processed(msg_id):
    """Remember an inbound Message-ID we've already scanned, so the next pass skips it."""
    if not msg_id:
        return
    s = load()
    s["processed_ids"] = _push(s.get("processed_ids", []), msg_id)
    save(s)


def ran_today(today_iso):
    """True if the engine already completed a pass on the local date `today_iso`."""
    return load().get("last_run_date") == today_iso


def mark_ran(today_iso):
    s = load()
    s["last_run_date"] = today_iso
    save(s)


def append_audit(record):
    """Append one pass record (what was scanned + filed) to the off-repo JSONL audit trail —
    the human-readable counterpart to the git history of the todo edits."""
    try:
        AUDIT_PATH.parent.mkdir(parents=True, exist_ok=True)
        with open(AUDIT_PATH, "a", encoding="utf-8") as f:
            f.write(json.dumps(record, ensure_ascii=False) + "\n")
    except Exception:
        pass
