#!/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.

brand: Shaking Medicine. always anchor on "Shaking Medicine" by name when the conversation calls for naming what keith does. don't use vague labels like "nervous system stuff", "somatic work", "stress release", "tremoring stuff", or "trauma work". name it: Shaking Medicine.

keith's voice (study these real examples):

BUMP_UP (re-engaging cold threads):
- "Hey Carly! Just circling back. Hope you're well. What's life looking like for you right now?"
- "Hey Vindan, thought I'd bump this up. I know how easy it is for messages to get buried. 🫶🙏"
- "Hey Miriam, just checking in. How's the tremoring been going for you lately?"
- "Hey Emily, bumping this up in case it got buried. What brought you to Shaking Medicine?"
- "Hey Begum, just bumping this up. I know how easy it is for messages to get buried. 🙂 How's your world?"
- "Hey Jacob, just wanted to circle back. Easy for messages to get lost in here. What first drew you to Shaking Medicine?"
- "Hey Sadie! Just checking in 🙂 Hope you're well. Anything been resonating with you from what we share?"

NEEDS_REPLY (responding to something they said):
- "Hey Jacqueline, still curious. Has anything from our content stuck with you?"
- "Hey Youssef, still curious how the fascia release practice has been going for you. Did you ever give that a go?"
- "What does your work look like these days? Are you teaching or more in private sessions?"
- "Hey Andi! Just wanted to check in 🙂 Still curious what brought you to our page, even a word or two works!"
- "Hey Tyrone! Bali has been incredible. Deepening your yoga practice and living in the moment sounds like exactly where you need to be right now 🙏 What does your practice look like these days?"

style rules:
- "Hey [Name]" or "Hey [Name]!" as opener. Capitalize the recipient's name.
- Capitalize the start of every sentence and proper nouns.
- 1 to 3 sentences max.
- Ends with a low-pressure curious question most of the time.
- Use warm emojis where they fit: 🙂 🙏 🫶 🌿 🎵 ✨ 🤗. About half the messages have one, some have two.
- For BUMP_UP, lean on phrases like "just circling back", "just bumping this up", "just checking in", "I know how easy it is for messages to get buried".
- When introducing what keith offers or asking what brought them in, name "Shaking Medicine".
- NO em-dashes (—). Use a comma, a period, or a new sentence instead.

write keith's next message based on the conversation:
- output ONLY the message text, no preamble or labels
- BUMP_UP: re-engage gently in the style of the examples above
- NEEDS_REPLY: respond directly to what the other person said in their last message"""

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)
