"""Token management for upstream control plane authentication."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Optional

import httpx

logger = logging.getLogger("radix_edge.upstream")


async def exchange_onboarding_token(
    api_base: str, cluster_id: str, tenant_id: str, one_time_token: str
) -> str:
    """Exchange one-time onboarding token for long-lived cluster token."""
    url = f"{api_base.rstrip('/')}/v1/clusters/{cluster_id}/auth/exchange"
    headers = {
        "X-Radix-One-Time-Token": one_time_token,
        "X-Radix-Tenant-Id": tenant_id,
        "Content-Type": "application/json",
    }

    async with httpx.AsyncClient(timeout=30.0) as client:
        resp = await client.post(url, headers=headers)
        resp.raise_for_status()
        data = resp.json()
        cluster_token = data.get("cluster_token")
        if not cluster_token:
            raise RuntimeError("Exchange response missing cluster_token")
        return cluster_token


def persist_token(token: str, token_file: str) -> None:
    """Write token to disk with restrictive permissions (owner rw only)."""
    path = Path(token_file)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(token)
    path.chmod(0o600)
    logger.info("Persisted cluster token to %s", path)


def load_token(token_file: str) -> Optional[str]:
    """Load token from persisted file. Returns None if file doesn't exist."""
    path = Path(token_file)
    if not path.exists():
        return None
    token = path.read_text().strip()
    return token if token else None


async def resolve_token(
    api_base: str,
    cluster_id: str,
    tenant_id: str,
    cluster_token: str,
    one_time_token: str,
    token_file: str,
) -> str:
    """Resolve cluster token from config, file, or onboarding exchange.

    Priority: env var > persisted file > one-time exchange.
    Raises RuntimeError if no token can be resolved.
    """
    if cluster_token:
        logger.info("Using cluster token from environment")
        return cluster_token

    file_token = load_token(token_file)
    if file_token:
        logger.info("Loaded cluster token from %s", token_file)
        return file_token

    if one_time_token:
        logger.info("Exchanging one-time token for long-lived token...")
        token = await exchange_onboarding_token(api_base, cluster_id, tenant_id, one_time_token)
        persist_token(token, token_file)
        return token

    raise RuntimeError(
        "No cluster token available. Set RADIX_CLUSTER_TOKEN, RADIX_ONE_TIME_TOKEN, "
        f"or ensure token file exists at {token_file}"
    )
