"""Dependency-free Tracewell client. Records metadata, never prompts or provider secrets."""
import json
import time
from urllib.request import Request, build_opener, HTTPRedirectHandler
from urllib.parse import urlparse
from urllib.error import HTTPError, URLError


class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None


class Tracewell:
    FIELDS = {
        "usage": {"eventId", "provider", "model", "inputTokens", "outputTokens", "costUsd", "inputRatePerMillion", "outputRatePerMillion", "automationId", "occurredAt"},
        "runs": {"eventId", "automationId", "status", "recordsProcessed", "durationMs", "occurredAt"},
    }

    def __init__(self, base_url, api_key, max_retries=2):
        url = urlparse(base_url)
        if url.scheme != "https" and not (url.scheme == "http" and url.hostname in ("localhost", "127.0.0.1", "::1")):
            raise ValueError("Use HTTPS; HTTP is only allowed on loopback")
        if not url.netloc or url.username or url.password or url.query or url.fragment or url.path not in ("", "/"):
            raise ValueError("base_url must be a plain origin")
        if not api_key or not isinstance(api_key, str):
            raise ValueError("An API key is required")
        if not isinstance(max_retries, int) or not 0 <= max_retries <= 3:
            raise ValueError("max_retries must be between 0 and 3")
        self.base_url, self.api_key = base_url.rstrip("/"), api_key
        self.max_retries, self.opener = max_retries, build_opener(NoRedirect())

    def usage(self, **event):
        return self._send("usage", event)

    def run(self, **event):
        return self._send("runs", event)

    def _send(self, kind, event):
        unknown = set(event) - self.FIELDS[kind]
        if unknown:
            raise ValueError("Unsupported metadata fields: " + ", ".join(sorted(unknown)))
        if not isinstance(event.get("eventId"), str) or not event["eventId"].strip() or len(event["eventId"]) > 200:
            raise ValueError("A stable eventId is required; use your logical operation ID")
        body = json.dumps(event, allow_nan=False).encode("utf-8")
        for attempt in range(self.max_retries + 1):
            req = Request(self.base_url + "/api/v1/" + kind, data=body, headers={"Content-Type": "application/json", "Authorization": "Bearer " + self.api_key}, method="POST")
            try:
                with self.opener.open(req, timeout=10) as response:
                    return json.load(response)
            except HTTPError as error:
                if attempt == self.max_retries or not (error.code == 429 or error.code >= 500):
                    raise RuntimeError("Tracewell rejected the event (HTTP %s)" % error.code) from None
            except (URLError, TimeoutError, OSError):
                if attempt == self.max_retries:
                    raise RuntimeError("Tracewell could not receive the event; retry with the same eventId") from None
            time.sleep(min(2, 0.25 * (2 ** attempt)))
