"""HTTP catalog registration and span tracking."""

from __future__ import annotations

import json
import logging
import os
import secrets
import time
from dataclasses import dataclass, field
from typing import Optional
from urllib.error import URLError
from urllib.request import Request, urlopen

logger = logging.getLogger(__name__)


def _new_hex_id(n_bytes: int = 16) -> str:
    return secrets.token_hex(n_bytes)


@dataclass
class HttpSpan:
    """Represents a single HTTP request span."""

    trace_id: str
    span_id: str
    _fn: str = field(repr=False)
    _started_at: int = field(repr=False)
    _client: object = field(repr=False)  # ServiceBridge, avoid circular import
    _input_buf: bytes = field(repr=False)

    def end(self, status_code: int = 0, error: str = "", success: Optional[bool] = None) -> None:
        """Close the span and report telemetry."""
        if success is None:
            success = 0 < status_code < 400
        output_buf = json.dumps({"statusCode": status_code, "error": error}).encode()
        self._client._report_call(
            self.trace_id,
            self.span_id,
            self._fn,
            self._started_at,
            self._input_buf,
            success,
            1,
            output_buf,
            error,
        )


def extract_trace_from_headers(headers: dict[str, str]) -> tuple[str, str]:
    """Extract trace context from HTTP headers.

    Returns (trace_id, parent_span_id).
    Priority: W3C traceparent > x-trace-id > generate new.
    """
    lower = {k.lower(): v for k, v in headers.items()}

    if tp := lower.get("traceparent", ""):
        parts = tp.strip().split("-")
        if len(parts) == 4 and parts[0] == "00" and len(parts[1]) == 32 and len(parts[2]) == 16:
            return parts[1], parts[2]

    if x_trace := lower.get("x-trace-id", ""):
        return x_trace.strip(), ""

    return _new_hex_id(16), ""


def register_http_endpoint(
    admin_url: str,
    service_key: str,
    service_name: str,
    method: str,
    route: str,
    instance_id: str = "",
    endpoint: str = "",
    allowed_callers: Optional[list[str]] = None,
) -> None:
    """Register an HTTP endpoint in the ServiceBridge catalog."""
    payload = json.dumps(
        {
            "service_name": service_name,
            "method": method,
            "route_pattern": route,
            "instance_id": instance_id,
            "endpoint": endpoint,
            "allowed_callers": allowed_callers or [],
        }
    ).encode()

    req = Request(
        f"{admin_url}/api/http/register",
        data=payload,
        headers={"Content-Type": "application/json", "x-service-key": service_key},
        method="POST",
    )
    try:
        resp = urlopen(req, timeout=10)
        if resp.status not in (200, 201):
            body = resp.read().decode(errors="replace")
            raise RuntimeError(f"register_http_endpoint: status {resp.status}: {body}")
    except URLError as exc:
        raise RuntimeError(f"register_http_endpoint: {exc}") from exc
