#!/usr/bin/env python3
"""Compile production/flow/*_SHOTS.md into Flow Auto-Pilot prompt banks.

The flowext extension types prompt TEXT only — attached characters and the
model/output-count are composer state set by hand once per batch. So shots are
grouped into one bank per (tier, attach-set); John opens the RSG Flow project,
attaches that bank's characters, sets the model (Fast/Quality) and 1x, then the
bank is enqueued and drains unattended. 2 takes per shot per the spend doctrine.

Usage:
  make_flow_bank.py               # write banks to ~/Documents/flowext/banks/rsg/
  make_flow_bank.py --enqueue N   # POST bank number N to localhost:8017/enqueue
"""
import json
import re
import sys
import urllib.request
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
SHEETS = ["TRACK1", "TRACK2", "TRACK3", "TRACK4", "TRACK5", "TRACK6", "TRACK7",
          "SHIFTS", "EXTRAS"]
BANKS = Path.home() / "Documents/flowext/banks/rsg"
SKIP = {"Logging", "t1_whitelabel", "attract_loop", "intro_qual"}  # done or cut
TAKES = 2
SERVER = "http://localhost:8017"


def parse():
    shots = []  # (id, chars tuple, quality bool, prompt)
    for name in SHEETS:
        text = (ROOT / f"production/flow/{name}_SHOTS.md").read_text()
        for m in re.finditer(r"^## (.+?)\n(.*?)(?=^## |\Z)", text, re.M | re.S):
            header, body = m.group(1), m.group(2)
            sid = header.split()[0]
            if sid in SKIP:
                continue
            quality = "QUALITY" in header
            am = re.search(r"\[attach: ([^\]]+)\]", header) or \
                 re.search(r"\[([^\]]+)\]", header)
            chars = () if not am or am.group(1) == "no characters" else \
                tuple(c.strip() for c in am.group(1).split(","))
            lines = [l.strip() for l in body.strip().splitlines() if l.strip()]
            if lines and lines[0].startswith("(") and lines[0].endswith(")"):
                lines = lines[1:]  # production note, not paste text
            prompt = re.sub(r"\s+", " ", " ".join(lines)).strip()
            if len(prompt) < 80:  # header wrap fragments / non-prompt sections
                print(f"  !! skipping {sid}: body too short ({len(prompt)} ch)")
                continue
            shots.append((sid, chars, quality, prompt))
    return shots


def slug(chars):
    return "+".join(re.sub(r"^the ", "", c.lower()).replace(" ", "") for c in chars) or "nochars"


def main():
    shots = parse()
    groups = {}  # (quality, chars) -> [shots] — keep sheet order within a group
    for s in shots:
        groups.setdefault((s[2], s[1]), []).append(s)
    # fast banks first (bulk of the game), quality after; big groups first
    order = sorted(groups, key=lambda k: (k[0], -len(groups[k])))
    BANKS.mkdir(parents=True, exist_ok=True)
    for old in BANKS.glob("*.jsonl"):
        old.unlink()
    for n, key in enumerate(order, 1):
        quality, chars = key
        model = "Veo 3.1 - Quality" if quality else "Veo 3.1 - Fast"
        path = BANKS / f"{n:02d}__{'quality' if quality else 'fast'}__{slug(chars)}.jsonl"
        with open(path, "w") as f:
            for sid, _, _, prompt in groups[key]:
                for take in range(1, TAKES + 1):
                    f.write(json.dumps({
                        "id": f"rsg_{sid}__t{take}", "kind": "video", "model": model,
                        "title": f"{sid} take {take}", "prompt": prompt,
                        "category": "rsg"}) + "\n")
        gens = len(groups[key]) * TAKES
        cr = gens * (100 if quality else 10)
        print(f"{path.name}: {len(groups[key])} shots x{TAKES} = {gens} gens ~{cr} cr"
              f"  [attach: {', '.join(chars) or 'none'}]")
    if len(sys.argv) > 2 and sys.argv[1] == "--enqueue":
        bank = sorted(BANKS.glob(f"{int(sys.argv[2]):02d}__*.jsonl"))[0]
        for line in bank.read_text().splitlines():
            req = urllib.request.Request(SERVER + "/enqueue", line.encode(),
                                         {"Content-Type": "application/json"})
            urllib.request.urlopen(req, timeout=5).read()
        print(f"enqueued {bank.name}")


if __name__ == "__main__":
    main()
