#!/usr/bin/env python3
"""
Keith Instagram Full Inbox Scanner
- Fetches ALL threads with full message history
- Categorizes: BUMP_UP / NEEDS_REPLY / ACTIVE
- Generates personalized response suggestions via Claude
- Resume-capable: saves progress, skips already-done threads
- Output: follow_up_FULL.csv + summary report
"""

import csv
import json
import os
import shutil
import time
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import unquote

import anthropic
import rookiepy
from instagrapi import Client
from instagrapi.exceptions import ClientError, DirectThreadNotFound

# ── Config ──────────────────────────────────────────────────────────────────
IG_USERNAME     = "shakingmedicine"
IG_PASSWORD     = os.environ.get("IG_PASSWORD", "")
MAX_THREADS     = 2000       # fetch up to this many threads
MSGS_PER_THREAD = 30         # full history per thread
DELAY_MIN       = 1.5        # seconds between thread fetches
DELAY_MAX       = 3.0        # seconds between thread fetches
PROGRESS_FILE   = Path(__file__).parent / "progress.json"
OUTPUT_CSV      = Path(__file__).parent / "follow_up_FULL.csv"
SESSION_FILE    = Path(__file__).parent / "session.json"

# ── Claude prompt for response suggestions ──────────────────────────────────
SYSTEM_PROMPT = """you are helping keith motes (@shakingmedicine), an australian shaking medicine / TRE coach.
his niche: somatic healing, trauma release, nervous system regulation.
his offer: 1-on-1 coaching, online group programs, skool community.
his style: warm, curious, genuine. not pushy. asks questions. meets people where they are.

you write short instagram DM suggestions for keith. always:
- lowercase, conversational, no emojis unless matching the vibe
- max 2-3 sentences
- reference something specific from the conversation history
- genuine curiosity, not sales pressure
- for BUMP_UP: re-engage gently, pick up thread naturally
- for NEEDS_REPLY: respond to what they actually said"""

def get_suggestion(client: anthropic.Anthropic, thread_summary: str, follow_up_type: str, display_name: str) -> str:
    prompt = f"""conversation history with {display_name}:

{thread_summary}

follow_up_type: {follow_up_type}

write keith's next message. one option only, no explanation."""

    try:
        msg = client.messages.create(
            model="claude-haiku-4-5-20251001",
            max_tokens=150,
            system=SYSTEM_PROMPT,
            messages=[{"role": "user", "content": prompt}]
        )
        return msg.content[0].text.strip()
    except Exception as e:
        return f"[suggestion failed: {e}]"

# ── Auth ─────────────────────────────────────────────────────────────────────
print("logging in via chrome session...")
cl = Client()
cl.delay_range = [DELAY_MIN, DELAY_MAX]

cookies  = rookiepy.chrome(domains=["instagram.com"])
session_id = unquote({c["name"]: c["value"] for c in cookies}["sessionid"])
cl.login_by_sessionid(session_id)
cl.dump_settings(SESSION_FILE)
my_id = str(cl.user_id)
print(f"logged in as: {cl.account_info().username} (id: {my_id})")

# ── Claude client ─────────────────────────────────────────────────────────────
anthropic_client = anthropic.Anthropic()

# ── Load progress ─────────────────────────────────────────────────────────────
progress = {}
if PROGRESS_FILE.exists():
    with open(PROGRESS_FILE) as f:
        progress = json.load(f)
    print(f"resuming: {len(progress)} threads already processed")

def save_progress():
    with open(PROGRESS_FILE, "w") as f:
        json.dump(progress, f)

# ── Fetch all threads ─────────────────────────────────────────────────────────
print(f"\nfetching up to {MAX_THREADS} threads...")
threads = cl.direct_threads(amount=MAX_THREADS)
print(f"found {len(threads)} threads total\n")

# ── CSV setup ─────────────────────────────────────────────────────────────────
fieldnames = [
    "handle", "display_name", "follow_up_type",
    "last_msg_date", "last_sender",
    "conversation_summary", "keith_last_msg",
    "other_last_msg", "suggested_reply",
    "thread_id"
]

existing_ids = set()
if OUTPUT_CSV.exists():
    with open(OUTPUT_CSV) as f:
        for row in csv.DictReader(f):
            existing_ids.add(row["thread_id"])

# defensive backup of existing CSV
if OUTPUT_CSV.exists() and OUTPUT_CSV.stat().st_size > 0:
    bak = OUTPUT_CSV.with_name(f"follow_up_FULL.csv.bak-{datetime.now().strftime('%Y%m%d-%H%M%S')}")
    shutil.copy2(OUTPUT_CSV, bak)
    print(f"backup written: {bak.name}")
csv_file = open(OUTPUT_CSV, "a", newline="", encoding="utf-8")
writer   = csv.DictWriter(csv_file, fieldnames=fieldnames)
if not OUTPUT_CSV.exists() or OUTPUT_CSV.stat().st_size == 0:
    writer.writeheader()

# ── Process threads ──────────────────────────────────────────────────────────
bump_up_count   = 0
needs_reply_count = 0
skipped         = 0
errors          = 0

for i, thread in enumerate(threads):
    thread_id = str(thread.id)

    # skip already processed
    if thread_id in progress or thread_id in existing_ids:
        skipped += 1
        continue

    try:
        users = [u for u in thread.users if str(u.pk) != my_id]
        if not users:
            continue

        other       = users[0]
        handle      = f"@{other.username}"
        display_name = other.full_name or other.username

        # fetch full thread
        full_thread = cl.direct_thread(thread_id, amount=MSGS_PER_THREAD)
        messages    = list(reversed(full_thread.messages))

        if not messages:
            continue

        # build conversation summary
        summary_lines = []
        keith_last_msg  = ""
        other_last_msg  = ""
        last_sender     = ""
        last_msg_date   = ""

        for m in messages:
            sender_name = "keith" if str(m.user_id) == my_id else display_name
            txt = getattr(m, "text", None) or f"[{m.item_type}]"
            ts  = m.timestamp.strftime("%d.%m.%Y") if hasattr(m.timestamp, "strftime") else ""
            summary_lines.append(f"[{ts}] {sender_name}: {txt[:200]}")

        # last message info
        last_msg       = messages[-1]
        last_sender_id = str(last_msg.user_id)
        keith_sent_last = (last_sender_id == my_id)
        last_sender    = "KEITH" if keith_sent_last else "OTHER"
        last_msg_date  = last_msg.timestamp.strftime("%Y-%m-%d %H:%M") if hasattr(last_msg.timestamp, "strftime") else ""

        # get last messages from each side
        for m in reversed(messages):
            if str(m.user_id) == my_id and not keith_last_msg:
                keith_last_msg = (getattr(m, "text", None) or f"[{m.item_type}]")[:300]
            elif str(m.user_id) != my_id and not other_last_msg:
                other_last_msg = (getattr(m, "text", None) or f"[{m.item_type}]")[:300]
            if keith_last_msg and other_last_msg:
                break

        follow_up_type = "BUMP_UP" if keith_sent_last else "NEEDS_REPLY"
        convo_summary  = "\n".join(summary_lines[-12:])  # last 12 messages for context

        # generate suggestion
        suggestion = get_suggestion(
            anthropic_client,
            convo_summary,
            follow_up_type,
            display_name
        )

        row = {
            "handle":               handle,
            "display_name":         display_name,
            "follow_up_type":       follow_up_type,
            "last_msg_date":        last_msg_date,
            "last_sender":          last_sender,
            "conversation_summary": convo_summary.replace("\n", " | "),
            "keith_last_msg":       keith_last_msg,
            "other_last_msg":       other_last_msg,
            "suggested_reply":      suggestion,
            "thread_id":            thread_id,
        }

        writer.writerow(row)
        csv_file.flush()

        progress[thread_id] = True
        save_progress()

        if follow_up_type == "BUMP_UP":
            bump_up_count += 1
        else:
            needs_reply_count += 1

        status = f"[{follow_up_type}] {handle} — {last_msg_date}"
        print(f"  {i+1}/{len(threads)} {status}")

    except DirectThreadNotFound:
        errors += 1
        progress[thread_id] = "error"
        save_progress()
    except ClientError as e:
        print(f"  rate limit hit at {i}, sleeping 30s... ({e})")
        time.sleep(30)
        errors += 1
    except Exception as e:
        print(f"  error on {i} ({thread_id}): {e}")
        errors += 1
        progress[thread_id] = "error"
        save_progress()

csv_file.close()

# ── Summary ───────────────────────────────────────────────────────────────────
print(f"""
═══════════════════════════════════════
SCAN COMPLETE
═══════════════════════════════════════
threads found:    {len(threads)}
processed:        {bump_up_count + needs_reply_count}
skipped (cached): {skipped}
errors:           {errors}

BUMP_UP:          {bump_up_count}
NEEDS_REPLY:      {needs_reply_count}

output: {OUTPUT_CSV}
═══════════════════════════════════════
""")
