# Pause, resume or stop a campaign, checking first that the action is allowed. Python 3.9+ with requests.
#   ACTION=pause|resume|stop CAMPAIGN_ID=cmp_... python campaign-action.py
# Every request runs, so after an uncertain outcome the script reads the campaign before sending again.
import json
import os
import sys
import time

import requests

base = os.environ.get("RELATIONSAI_API_BASE", "https://voice-api.relationsai.com/v1")
campaign_id = os.environ.get("CAMPAIGN_ID")
action = os.environ.get("ACTION")
if not campaign_id or action not in ("pause", "resume", "stop"):
    sys.exit("Set CAMPAIGN_ID (cmp_...) and ACTION (pause, resume or stop)")
target = {"pause": "paused", "resume": "running", "stop": "stopped"}[action]
auth = {"Authorization": f"Bearer {os.environ['RELATIONSAI_API_KEY']}"}


def read():
    r = requests.get(f"{base}/campaigns/{campaign_id}", headers=auth, timeout=30)
    campaign = r.json()
    if not r.ok:
        err = campaign["error"]
        sys.exit(f"{err['code']}: {err['message']} (request {err['request_id']})")
    return campaign


campaign = read()
for attempt in range(1, 6):
    if campaign["status"] == target and attempt > 1:
        print(f"{action}: {campaign['id']} is now {campaign['status']} (the earlier attempt took effect)")
        sys.exit(0)
    if not campaign["capabilities"][action]:
        sys.exit(f"{action} is not allowed while the campaign is {campaign['status']}")
    try:
        r = requests.post(f"{base}/campaigns/{campaign_id}/{action}", headers=auth, timeout=30)
    except requests.RequestException:
        # Timeout or network error: the action may have happened. Read the campaign before deciding.
        time.sleep(2**attempt)
        campaign = read()
        continue
    body = r.json()
    if r.ok:
        print(f"{action}: {body['id']} is now {body['status']}")
        sys.exit(0)
    err = body["error"]
    if err["code"] == "campaign_recipients_blocked":
        # Nothing was resumed. Create a new campaign with the pending recipients minus these, then stop this one.
        d = err["details"]
        sys.exit(f"Not resumed: {d['blocked_total']} recipients are blocked {json.dumps(d['by_reason'])}")
    if err["retry"] == "no":
        sys.exit(f"{err['code']}: {err['message']} (request {err['request_id']})")
    # "after" (wait as told) or "yes" (may have happened, for example campaign_outcome_unknown): read before resending.
    time.sleep(float(r.headers.get("Retry-After", 2**attempt)))
    print(f"{err['code']}; read the campaign before sending again")
    campaign = read()

sys.exit("Still not confirmed: read the campaign before doing anything else")
