#!/home/agent/venv/bin/python3
"""Plappi press reply-watch — closes the e-mail loop.

Scans Lena's inbox (lena@breact.ai) via MS Graph. When a reply arrives from a
known press target, it:
  1) marks the target 'replied',
  2) drafts a follow-up reply (pending item, type press_followup),
  3) WhatsApps Nemanja the original + the follow-up draft for approval.

State: /home/agent/plappi-marketing/data/reply-state.json (seen message ids).
First run only seeds (no flood of old mail). Cron-friendly. Mirrors
fred-mail-watch.py's Graph pattern.
"""
from __future__ import annotations

import json
import sys
import urllib.request
import urllib.parse
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from marketing_lib import (
    list_targets, set_target_status, insert_item, get_item, get_target,
    format_for_wa, wa_send, run_claude, log,
)
import press_outreach

SECRETS = "/home/agent/etc/secrets.env"
MAILBOX = "lena@breact.ai"
STATE = Path("/home/agent/plappi-marketing/data/reply-state.json")
SKIP = ["noreply", "no-reply", "mailer-daemon", "postmaster", "microsoft"]

FOLLOWUP_SYS = """Du bist die PR-Verantwortliche von Plappi und antwortest einer Redaktion/
einem:r Journalist:in, die auf deine Pitch-Mail GEANTWORTET hat. Schreib eine kurze, konkrete,
freundliche Antwort, die auf den Inhalt der eingegangenen Nachricht eingeht (Frage beantworten,
Material/Testgerät/Termin anbieten). Deutsch (oder Englisch, falls die Antwort englisch war).
80–140 Wörter, kein Floskel-Schluss mit Namen (Signatur wird automatisch angehängt).
OUTPUT: nur der Antworttext."""


def _sec():
    e = {}
    for l in open(SECRETS):
        if "=" in l and not l.startswith("#"):
            k, v = l.strip().split("=", 1); e[k] = v
    return e


def _token(s):
    data = urllib.parse.urlencode({
        "client_id": s["MS_CLIENT_ID"], "client_secret": s["MS_CLIENT_SECRET"],
        "scope": "https://graph.microsoft.com/.default", "grant_type": "client_credentials"}).encode()
    r = urllib.request.urlopen(
        f"https://login.microsoftonline.com/{s['MS_TENANT_ID']}/oauth2/v2.0/token", data=data, timeout=20)
    return json.loads(r.read())["access_token"]


def _inbox(tok):
    url = (f"https://graph.microsoft.com/v1.0/users/{MAILBOX}/mailFolders/inbox/messages"
           "?$top=25&$orderby=receivedDateTime%20desc"
           "&$select=id,subject,from,bodyPreview,receivedDateTime")
    req = urllib.request.Request(url, headers={"Authorization": "Bearer " + tok})
    return json.loads(urllib.request.urlopen(req, timeout=30).read()).get("value", [])


def _press_index():
    """email/domain → target row, for press targets that have a contact email."""
    by_email, by_domain = {}, {}
    for t in list_targets(channel="press"):
        c = (t["contact"] or "").lower().strip()
        if "@" in c:
            by_email[c] = t
            by_domain[c.split("@")[-1]] = t
    return by_email, by_domain


def run(dry: bool = False):
    state = json.loads(STATE.read_text()) if STATE.exists() else {}
    seen = set(state.get("seen", []))
    first = "seen" not in state
    try:
        s = _sec(); tok = _token(s); msgs = _inbox(tok)
    except Exception as e:
        log(f"reply-watch Graph error: {e}", "reply-watch"); return

    if first:
        state["seen"] = [m["id"] for m in msgs]
        if not dry:
            STATE.write_text(json.dumps(state))
        log(f"reply-watch erster Lauf: {len(msgs)} geseedet", "reply-watch"); return

    by_email, by_domain = _press_index()
    new = 0
    for m in msgs:
        mid = m["id"]
        if mid in seen:
            continue
        seen.add(mid)
        frm = (((m.get("from") or {}).get("emailAddress") or {}).get("address", "") or "").lower()
        if not frm or any(x in frm for x in SKIP):
            continue
        dom = frm.split("@")[-1] if "@" in frm else ""
        t = by_email.get(frm) or by_domain.get(dom)
        if not t:
            continue  # not a press contact → ignore (fred-mail-watch handles general inbox)
        subj = m.get("subject", "(kein Betreff)")
        prev = (m.get("bodyPreview") or "")[:400]
        if not dry:
            set_target_status(t["id"], "replied")
        # draft a follow-up
        try:
            prompt = (f"EINGEGANGENE ANTWORT von {t['name']} ({frm}):\n"
                      f"Betreff: {subj}\n\"\"\"\n{prev}\n\"\"\"\n\n"
                      f"{press_outreach.PRODUCT_FACTS}\n\nSchreib die passende Antwort.")
            body = run_claude(prompt, FOLLOWUP_SYS, label="press_followup")
        except Exception as e:
            log(f"reply-watch draft err: {e}", "reply-watch")
            body = f"[Auto-Entwurf fehlgeschlagen — bitte manuell antworten an {frm}]"
        if dry:
            print(f"DRY reply from {t['name']} ({frm}) subj={subj}\n--draft--\n{body}\n"); new += 1; continue
        iid = insert_item(target_id=t["id"], channel="press", type_="press_followup",
                          platform=t["platform"], subject=f"Re: {subj}", body=body,
                          disclosure=None, thread_ref=subj, prompt_used=prev, model_used="haiku")
        wa_send(f"📨 *{t['name']} hat geantwortet!*\nVon: {frm}\nBetreff: {subj}\n\n{prev}\n\n"
                f"———\nFolge-Entwurf #{iid} bereit:")
        wa_send(format_for_wa(get_item(iid), get_target(t["id"])))
        log(f"reply from {t['name']} → followup #{iid}", "reply-watch")
        new += 1

    state["seen"] = list(seen)[-500:]
    if not dry:
        STATE.write_text(json.dumps(state))
    log(f"reply-watch done: {new} Antworten verarbeitet", "reply-watch")


if __name__ == "__main__":
    run(dry="--dry" in sys.argv)
