"""Cross the sealing rail with the writing rail, per the README's pre-registered rule.

Reads ~/data/1f916-quiet/seals.csv (one row per citizen, `fetch_seals.py`) and the
board copy in ~/data/1f916/ (`research/1f916-census/fetch.py`), and prints the four
counts for a window ending at the seal fetch's own time.
"""
import csv
import json
import os
import pathlib
import sys
import time

QUIET = pathlib.Path(os.path.expanduser("~/data/1f916-quiet"))
BOARD = pathlib.Path(os.path.expanduser("~/data/1f916"))
DAYS = int(sys.argv[1]) if len(sys.argv) > 1 else 7


def wrote_since(cutoff_ms):
    """Handles with a post or a comment created after `cutoff_ms`.

    The board rows name their author differently in the two streams, so every
    plausible key is tried and the one that resolves is used; a row whose author
    cannot be read is counted in `unattributed` and never silently dropped.
    """
    handles, unattributed, newest = set(), 0, 0
    for name in ("posts.jsonl", "comments.jsonl"):
        path = BOARD / name
        if not path.exists():
            print(f"missing {path}", file=sys.stderr)
            continue
        with open(path) as fh:
            for line in fh:
                try:
                    row = json.loads(line)
                except ValueError:
                    continue
                created = row.get("created_at") or 0
                newest = max(newest, created)
                if created <= cutoff_ms:
                    continue
                who = (row.get("handle") or row.get("author")
                       or row.get("citizen_handle") or row.get("author_handle"))
                if who:
                    handles.add(who)
                else:
                    unattributed += 1
    return handles, unattributed, newest


def main():
    rows = list(csv.DictReader(open(QUIET / "seals.csv")))
    fetched_at = int(os.path.getmtime(QUIET / "seals.csv") * 1000)
    cutoff = fetched_at - DAYS * 86400 * 1000

    def as_int(value):
        try:
            return int(value)
        except (TypeError, ValueError):
            return 0

    sealed_recently = set()
    ever_sealed = set()
    for r in rows:
        if r.get("latest_seal_id"):
            ever_sealed.add(r["handle"])
            when = max(as_int(r.get("sealed_at")), as_int(r.get("last_checked_at")))
            if when > cutoff:
                sealed_recently.add(r["handle"])

    writers, unattributed, newest = wrote_since(cutoff)
    known = {r["handle"] for r in rows}
    writers &= known                      # a writer the census page did not list
    errors = [r["handle"] for r in rows if r.get("error")]

    both = sealed_recently & writers
    quiet = sealed_recently - writers
    only_wrote = writers - sealed_recently
    neither = known - sealed_recently - writers

    print(f"board copy newest row: {time.strftime('%Y-%m-%d %H:%M', time.gmtime(newest / 1000))}Z")
    print(f"seal fetch:            {time.strftime('%Y-%m-%d %H:%M', time.gmtime(fetched_at / 1000))}Z")
    print(f"window:                {DAYS} days, cutoff "
          f"{time.strftime('%Y-%m-%d %H:%M', time.gmtime(cutoff / 1000))}Z")
    print(f"citizens:              {len(known)}  ({len(errors)} seal lookups failed)")
    print(f"ever sealed:           {len(ever_sealed)}")
    print(f"sealed in window:      {len(sealed_recently)}")
    print(f"wrote in window:       {len(writers)}  ({unattributed} rows had no readable author)")
    print()
    print(f"sealed and wrote:      {len(both)}")
    print(f"SEALED AND SILENT:     {len(quiet)}  = {100 * len(quiet) / len(known):.2f} % of citizens")
    print(f"wrote, never sealed:   {len(only_wrote)}")
    print(f"neither:               {len(neither)}")
    if quiet:
        print("\nsealed and silent, by newest seal activity:")
        by_time = sorted(quiet, key=lambda h: -max(
            as_int(next(r for r in rows if r["handle"] == h).get("sealed_at")),
            as_int(next(r for r in rows if r["handle"] == h).get("last_checked_at"))))
        for h in by_time[:20]:
            r = next(x for x in rows if x["handle"] == h)
            when = max(as_int(r.get("sealed_at")), as_int(r.get("last_checked_at")))
            print(f"  {h:34s} {r.get('latest_label','')[:24]:24s} "
                  f"{time.strftime('%Y-%m-%d %H:%M', time.gmtime(when / 1000))}Z "
                  f"checks={r.get('checks')}")


if __name__ == "__main__":
    main()
