#!/usr/bin/env python3
"""
Delete every artifact Workflow 0's 2026-04-13 15:22-15:38 run created for
Rachel Bergeron / NaturallyRachB.

Scope — strictly things created by THAT specific W0 run:
  1. Drive: Client Portal sheet (trash)
  2. Drive: Knowledge Base doc (trash)
  3. Drive: Brand Surface Guide HTML (trash)
  4. Drive: Products/ folder (trash)
  5. Drive: Campaigns/ folder (trash)
  6. Drive: Content/Posts/ folder (trash)
  7. FLSM Clients sheet row 9 (NaturallyRachB)
  8. FLSM Projects sheet row where client=NaturallyRachB AND name="Client Onboarding"
  9. FLSM Tasks sheet rows linked to that project
 10. EN Onboarding Queue sheet row 2 (our manual insert)
 11. Vercel project naturallyrachb-portal (domain detaches automatically)
 12. Local file .tmp/onboard_naturallyrachb_2026-04-13.json
 13. tools/onboard_scrape.py line 47 (naturallyrachb CLIENT_SHEETS entry)
 14. tools/apify_scrape.py line 48 (naturallyrachb CLIENT_SHEETS entry)

Usage:
    python3 .tmp/delete_w0_rachel.py           # dry run, lists actions only
    python3 .tmp/delete_w0_rachel.py --execute # live deletions
"""
import os, sys, json, time, urllib.request, urllib.parse, urllib.error, pathlib, argparse

ROOT = pathlib.Path(__file__).parent.parent
for line in (ROOT / ".env").read_text().splitlines():
    line = line.strip()
    if line and not line.startswith("#") and "=" in line:
        k, _, v = line.partition("=")
        os.environ.setdefault(k.strip(), v.strip())

GTOKEN_PATH = pathlib.Path.home() / ".config/google-workspace-mcp/profiles/emerson-north/tokens.json"
GCREDS_PATH = pathlib.Path.home() / ".config/google-workspace-mcp/profiles/emerson-north/credentials.json"

SHEETS = {
    "clients":  "1YzvFkX-aXTZQTKgPYejOuaLzxrligXIDquBeTZqv4Es",
    "projects": "1EZZafN29DAf95TTn-aS3eiUUB0C4eGq8i8lqu_3Za04",
    "tasks":    "1EVeY-oLF0GjQ2bm42_jbq73SlQzDfRWjOX-X3PCz4ZA",
    "queue":    "1FX0eDt9d322XYcOQRp8b9tXkRrrrHcSWJ9maXEwYk7k",
}

DRIVE_ITEMS = {
    "Client Portal sheet":         "1AbWVhUIXO9M-3fGW3dHmSk-0LktVwJS87iydSCTaltk",
    "Knowledge Base doc":          "1v37V0HcI6BQ91gJlgnY2a6cV3RA0fWo4KwQdFihoqgQ",
    "Brand Surface Guide HTML":    "1hjjIlzw2M20SX_V6BesdnVsse7EwxGpb",
    "Products/ folder":            "1acGfloNHo3lZUNMDBtZOrmilmKq_nWwM",
    "Campaigns/ folder":           "1tmvTULhfrRqH0fgaZigK9QgLEBpCYUJ_",
    "Content/Posts/ folder":       "17dggwDPPVppPsogTmHHBC-llqS8XWxZj",
}

VERCEL_PROJECT_ID = "prj_WRptAlKcOjbaAtiURd1CmBnisPUg"
VERCEL_PROJECT_NAME = "naturallyrachb-portal"

LOCAL_FILE = ROOT / ".tmp/onboard_naturallyrachb_2026-04-13.json"


# ── Auth helpers ──────────────────────────────────────────────────────────────

def google_token():
    t = json.loads(GTOKEN_PATH.read_text())
    if t.get("expiry_date", 0) / 1000 > time.time() + 60:
        return t["access_token"]
    c = json.loads(GCREDS_PATH.read_text())
    w = c.get("web") or c.get("installed", {})
    data = urllib.parse.urlencode({
        "client_id": w["client_id"], "client_secret": w["client_secret"],
        "refresh_token": t["refresh_token"], "grant_type": "refresh_token",
    }).encode()
    r = json.loads(urllib.request.urlopen(urllib.request.Request(
        "https://oauth2.googleapis.com/token", data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded"}), timeout=15).read())
    t["access_token"] = r["access_token"]
    t["expiry_date"] = int((time.time() + r["expires_in"]) * 1000)
    GTOKEN_PATH.write_text(json.dumps(t, indent=2))
    return t["access_token"]


def google_req(method, path, body=None, params=None, base="https://www.googleapis.com"):
    url = f"{base}{path}"
    if params:
        url += "?" + urllib.parse.urlencode(params)
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, method=method, headers={
        "Authorization": f"Bearer {google_token()}",
        "Content-Type": "application/json",
        "User-Agent": "flsm-w0-cleanup",
    })
    resp = urllib.request.urlopen(req, timeout=30)
    raw = resp.read()
    return json.loads(raw) if raw else None


def vercel_req(method, path, body=None):
    url = f"https://api.vercel.com{path}"
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, method=method, headers={
        "Authorization": f"Bearer {os.environ['VERCEL_TOKEN']}",
        "Content-Type": "application/json",
        "User-Agent": "flsm-w0-cleanup",
    })
    resp = urllib.request.urlopen(req, timeout=30)
    raw = resp.read()
    return json.loads(raw) if raw else None


# ── Actions ───────────────────────────────────────────────────────────────────

def trash_drive_item(label, file_id, execute):
    print(f"  DRIVE {label} ({file_id}) -> trash", end="")
    if not execute:
        print("  [dry-run]")
        return
    try:
        google_req("PATCH", f"/drive/v3/files/{file_id}",
                   body={"trashed": True},
                   params={"supportsAllDrives": "true"})
        print("  ✓")
    except urllib.error.HTTPError as e:
        print(f"  ✗ HTTP {e.code}: {e.read().decode()[:120]}")


def sheet_find_rows(sheet_id, range_, predicate):
    """Return (1-indexed) row numbers matching predicate(row)."""
    rows = google_req("GET", f"/v4/spreadsheets/{sheet_id}/values/{urllib.parse.quote(range_)}",
                      base="https://sheets.googleapis.com").get("values", [])
    return [(i + 1, r) for i, r in enumerate(rows) if predicate(r)]


def sheet_delete_row(sheet_id, sheet_gid, row_num_1indexed, execute):
    """Use batchUpdate deleteDimension. row_num_1indexed is 1-based (row 1 = header)."""
    if not execute:
        print(f"    would delete spreadsheet={sheet_id} gid={sheet_gid} row={row_num_1indexed}")
        return
    body = {"requests": [{"deleteDimension": {"range": {
        "sheetId": sheet_gid,
        "dimension": "ROWS",
        "startIndex": row_num_1indexed - 1,  # 0-based inclusive
        "endIndex": row_num_1indexed,         # 0-based exclusive
    }}}]}
    google_req("POST", f"/v4/spreadsheets/{sheet_id}:batchUpdate",
               body=body, base="https://sheets.googleapis.com")
    print(f"    ✓ deleted row {row_num_1indexed}")


def get_first_sheet_gid(sheet_id):
    meta = google_req("GET", f"/v4/spreadsheets/{sheet_id}",
                      params={"fields": "sheets.properties"},
                      base="https://sheets.googleapis.com")
    return meta["sheets"][0]["properties"]["sheetId"]


def delete_clients_row(execute):
    print("SHEETS: FLSM Clients — delete NaturallyRachB row")
    gid = get_first_sheet_gid(SHEETS["clients"])
    matches = sheet_find_rows(
        SHEETS["clients"], "Sheet1!A1:J50",
        lambda r: any("NaturallyRachB" in (c or "") for c in r),
    )
    for row_num, row in matches:
        print(f"  found row {row_num}: {row[:4]}")
        sheet_delete_row(SHEETS["clients"], gid, row_num, execute)
    if not matches:
        print("  (none found)")


def delete_projects_rows(execute):
    print("SHEETS: FLSM Projects — delete NaturallyRachB Client Onboarding project(s)")
    gid = get_first_sheet_gid(SHEETS["projects"])
    matches = sheet_find_rows(
        SHEETS["projects"], "Sheet1!A1:N500",
        lambda r: any("NaturallyRachB" in (c or "") for c in r),
    )
    for row_num, row in sorted(matches, key=lambda x: -x[0]):
        print(f"  found row {row_num}: {row[:6]}")
        sheet_delete_row(SHEETS["projects"], gid, row_num, execute)
    if not matches:
        print("  (none found)")


def delete_tasks_rows(execute):
    print("SHEETS: FLSM Tasks — delete NaturallyRachB tasks")
    gid = get_first_sheet_gid(SHEETS["tasks"])
    matches = sheet_find_rows(
        SHEETS["tasks"], "Sheet1!A1:T500",
        lambda r: any("NaturallyRachB" in (c or "") for c in r),
    )
    for row_num, row in sorted(matches, key=lambda x: -x[0]):
        print(f"  found row {row_num}: {row[:6]}")
        sheet_delete_row(SHEETS["tasks"], gid, row_num, execute)
    if not matches:
        print("  (none found)")


def delete_queue_row(execute):
    print("SHEETS: EN Onboarding Queue — delete NaturallyRachB row")
    gid = get_first_sheet_gid(SHEETS["queue"])
    matches = sheet_find_rows(
        SHEETS["queue"], "Sheet1!A1:K100",
        lambda r: any("NaturallyRachB" in (c or "") for c in r),
    )
    for row_num, row in sorted(matches, key=lambda x: -x[0]):
        print(f"  found row {row_num}: {row[:4]}")
        sheet_delete_row(SHEETS["queue"], gid, row_num, execute)
    if not matches:
        print("  (none found)")


def delete_drive_items(execute):
    print("DRIVE: trash 6 items")
    for label, fid in DRIVE_ITEMS.items():
        trash_drive_item(label, fid, execute)


def delete_vercel_project(execute):
    print(f"VERCEL: delete project {VERCEL_PROJECT_NAME} ({VERCEL_PROJECT_ID})", end="")
    if not execute:
        print("  [dry-run]")
        return
    try:
        vercel_req("DELETE", f"/v9/projects/{VERCEL_PROJECT_ID}")
        print("  ✓")
    except urllib.error.HTTPError as e:
        print(f"  ✗ HTTP {e.code}: {e.read().decode()[:200]}")


def delete_local_file(execute):
    print(f"LOCAL: remove {LOCAL_FILE}", end="")
    if not LOCAL_FILE.exists():
        print("  (not found)")
        return
    if not execute:
        print("  [dry-run]")
        return
    LOCAL_FILE.unlink()
    print("  ✓")


def edit_client_sheets_configs(execute):
    print("EDITS: remove naturallyrachb CLIENT_SHEETS entries")
    for rel in ("tools/onboard_scrape.py", "tools/apify_scrape.py"):
        path = ROOT / rel
        lines = path.read_text().splitlines(keepends=True)
        kept = [l for l in lines if "naturallyrachb" not in l]
        removed = len(lines) - len(kept)
        print(f"  {rel}: {removed} line(s) to remove", end="")
        if removed == 0:
            print("  (already clean)")
            continue
        if not execute:
            print("  [dry-run]")
            continue
        path.write_text("".join(kept))
        print("  ✓")


# ── Main ──────────────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--execute", action="store_true",
                        help="Actually perform deletions. Default is dry-run.")
    args = parser.parse_args()
    mode = "EXECUTE" if args.execute else "DRY RUN"
    print(f"=== Workflow 0 Rachel cleanup — {mode} ===\n")

    delete_drive_items(args.execute); print()
    delete_clients_row(args.execute); print()
    delete_projects_rows(args.execute); print()
    delete_tasks_rows(args.execute); print()
    delete_queue_row(args.execute); print()
    delete_vercel_project(args.execute); print()
    delete_local_file(args.execute); print()
    edit_client_sheets_configs(args.execute); print()

    print(f"=== {mode} complete ===")


if __name__ == "__main__":
    main()
