"""RedactTool REST example. Supply your own endpoint and key.
No network activity occurs until this script is explicitly executed.
Requires: pip install requests
"""
import os
import time
import uuid
from pathlib import Path
from urllib.parse import urlparse
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

base = os.environ["REDACTTOOL_BASE_URL"].rstrip("/")
key = os.environ["REDACTTOOL_API_KEY"]
source = Path(os.environ.get("REDACTTOOL_FILE", "sample.txt"))
parsed = urlparse(base)
if parsed.scheme != "https" and parsed.hostname not in {"localhost", "127.0.0.1"} and os.environ.get("REDACTTOOL_ALLOW_HTTP_TRIAL") != "1":
    raise ValueError("Use HTTPS, or explicitly set REDACTTOOL_ALLOW_HTTP_TRIAL=1 for non-confidential trial files")
output = source.with_name(source.stem + "-redacted" + source.suffix)
if output.exists():
    raise FileExistsError(output)
session = requests.Session()
# Retry safe reads when an idle connection closes. Do not replay POST bodies.
retry = Retry(total=3, connect=3, read=3, backoff_factor=0.5,
              allowed_methods=frozenset({"GET"}), status_forcelist=(502, 503, 504))
for scheme in ("https://", "http://"):
    session.mount(scheme, HTTPAdapter(max_retries=retry))
session.headers["Authorization"] = "Bearer " + key

def checked(response):
    response.raise_for_status()
    return response.json()

with source.open("rb") as content:
    uploaded = checked(session.post(base + "/v1/files",
        files={"file": (source.name, content)}, timeout=(15, 120)))
# Keep this ID if you retry this same creation request.
request_id = uuid.uuid4().hex
print("Keep file_id and Idempotency-Key for recovery:", uploaded["file_id"], request_id)
job = checked(session.post(base + "/v1/redactions",
    headers={"Idempotency-Key": request_id},
    json={"file_id": uploaded["file_id"], "mode": "placeholder"},
    timeout=(15, 60)))
print("Job:", job["id"])
# A local wait timeout does not cancel server processing.
deadline = time.monotonic() + 3600
while job["status"] not in {"completed", "failed"}:
    if time.monotonic() >= deadline:
        raise TimeoutError("Resume polling this job ID; do not create a new job")
    time.sleep(5)
    job = checked(session.get(base + "/v1/redactions/" + job["id"],
        timeout=(15, 60)))
if job["status"] == "failed":
    raise RuntimeError(job.get("error") or "job_failed")
# Use a known same-origin path, never an arbitrary returned host.
with session.get(base + "/v1/redactions/" + job["id"] + "/file",
                 stream=True, timeout=(15, 120)) as result:
    result.raise_for_status()
    with output.open("xb") as saved:
        for chunk in result.iter_content(65536):
            saved.write(chunk)
print("Saved:", output)
