#!/usr/bin/env python3
"""Regenerate suggested_reply for rows where it failed.

Uses claude CLI at absolute path. Backs up CSV before writing.
Parallel via ThreadPoolExecutor (max_workers=4).
"""
import csv, subprocess, os, shutil, sys
from datetime import datetime
from pathlib import Path

def _strip_dashes(s):
    import re as _re
    if not s: return s
    s = s.replace(" — ", ", ").replace(" —", ",").replace("— ", ", ").replace("—", ",")
    return _re.sub(r" {2,}", " ", s)


from concurrent.futures import ThreadPoolExecutor, as_completed

BASE = Path(__file__).parent if Path(__file__).parent.name == "keith-dm-scanner" else Path("/Users/daichi/keith-dm-scanner")
DM_CSV = BASE / "follow_up_FULL.csv"
CLAUDE_BIN = "/Users/daichi/.local/bin/claude"
ENV = {k: v for k, v in os.environ.items() if k != "ANTHROPIC_API_KEY"}
WORKERS = 1

SYSTEM_PROMPT = """you are helping keith motes (@shakingmedicine), an australian shaking medicine / TRE coach.
niche: somatic healing, trauma release, nervous system regulation.
offer: 1-on-1 coaching, online group programs, skool community.
brand name: Shaking Medicine. always anchor on "Shaking Medicine" by name when describing what keith does or what they could try. never use vague labels like "nervous system stuff", "somatic work", "stress release", "trauma work" as the hook. name it: Shaking Medicine.
style: warm, curious, genuine. not pushy. asks questions. meets people where they are.
emoji: keith uses occasional warm ones like 🙂 🪷 🙏 🫶 ✨ where they fit naturally. include 1-2 where they match the vibe, not every message needs them.

write a short instagram DM for keith:
- conversational and warm. capitalize the start of sentences and proper names (people, places).
- max 2-3 sentences, reference something specific from the conversation
- genuine curiosity, not sales pressure
- when introducing what keith offers, say "Shaking Medicine" by name (capitalized)
- 1-2 warm emojis where they match the vibe
- no em-dashes (—). use a comma, a period, or a new sentence instead
- BUMP_UP: re-engage gently; NEEDS_REPLY: respond to what they said
- output the message text only, no preamble"""

def get_suggestion(row):
    summary = row["conversation_summary"].replace(" | ", "\n")[-1200:]
    follow_up_type = row["follow_up_type"]
    display_name = row["display_name"]
    prompt = f"""{SYSTEM_PROMPT}

conversation with {display_name}:
{summary}

type: {follow_up_type} — write keith's reply:"""
    try:
        r = subprocess.run(
            [CLAUDE_BIN, "-p", prompt],
            capture_output=True, text=True, timeout=60, env=ENV,
        )
        text = r.stdout.strip()
        if text and r.returncode == 0:
            return text
        return f"[failed: rc={r.returncode} {r.stderr[:80]}]"
    except Exception as e:
        return f"[failed: {e}]"

# load CSV
with open(DM_CSV, encoding="utf-8") as f:
    reader = csv.DictReader(f)
    fieldnames = reader.fieldnames
    rows = list(reader)
print(f"loaded {len(rows)} rows", flush=True)

# pick rows that need regeneration
needs_redo = [
    (i, r) for i, r in enumerate(rows)
    if not r["suggested_reply"] or r["suggested_reply"].startswith("[")
]
print(f"need re-generation: {len(needs_redo)}", flush=True)

# backup
bak = DM_CSV.with_name(f"follow_up_FULL.csv.bak-{datetime.now().strftime('%Y%m%d-%H%M%S')}-presuggest")
shutil.copy2(DM_CSV, bak)
print(f"backup written: {bak.name}", flush=True)

# parallel re-generate
done = 0
total = len(needs_redo)
with ThreadPoolExecutor(max_workers=WORKERS) as ex:
    futures = {ex.submit(get_suggestion, r): (i, r) for i, r in needs_redo}
    for fut in as_completed(futures):
        i, r = futures[fut]
        new_sug = fut.result()
        rows[i]["suggested_reply"] = _strip_dashes(new_sug)
        done += 1
        if done % 25 == 0 or done == total:
            print(f"  [{done}/{total}] {r['handle']} → {new_sug[:60].replace(chr(10),' ')}", flush=True)
            # incremental write every 25 to limit blast radius
            with open(DM_CSV, "w", newline="", encoding="utf-8") as f:
                w = csv.DictWriter(f, fieldnames=fieldnames)
                w.writeheader(); w.writerows(rows)

# final write
with open(DM_CSV, "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=fieldnames)
    w.writeheader(); w.writerows(rows)
print(f"\ndone. regenerated {done} suggestions.", flush=True)
