"""HTTP client for talking to the control plane."""

from typing import Any

import httpx

from . import config


class ApiError(Exception):
    """User-friendly API error with message from server."""

    def __init__(self, message: str, status_code: int = 0) -> None:
        self.message = message
        self.status_code = status_code
        super().__init__(message)


def _raise_for_status(resp: httpx.Response) -> None:
    """Raise ApiError with the server's error message, not raw httpx text."""
    if resp.is_success:
        return
    try:
        body = resp.json()
        error = body.get("error", {})
        message = error.get("message", resp.text)
    except Exception:
        message = resp.text
    raise ApiError(message, resp.status_code)


def _get_client(env: str | None = None, timeout: int = 30) -> tuple[httpx.Client, dict[str, Any]]:
    env_config = config.get_env_config(env)
    endpoint: str | None = env_config.get("endpoint")
    token: str | None = env_config.get("access_token")

    if not endpoint:
        raise ValueError(f"No endpoint configured for environment '{config.get_current_env()}'")
    if not token:
        raise ValueError("Not logged in. Run 'loony login' first.")

    client = httpx.Client(
        base_url=endpoint,
        headers={"Authorization": f"Bearer {token}"},
        timeout=timeout,
    )
    return client, env_config


def me(env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.get("/api/v1/me")
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def health(env: str | None = None) -> dict[str, Any]:
    env_config = config.get_env_config(env)
    endpoint: str | None = env_config.get("endpoint")
    if not endpoint:
        raise ValueError(f"No endpoint configured for environment '{config.get_current_env()}'")

    resp = httpx.get(f"{endpoint}/healthz", timeout=10)
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def secrets_set(name: str, secret_name: str, value: str, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.post(f"/api/v1/services/{name}/secrets", json={"secret_name": secret_name, "value": value})
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def secrets_list(name: str, env: str | None = None) -> list[str]:
    client, _ = _get_client(env)
    resp = client.get(f"/api/v1/services/{name}/secrets")
    _raise_for_status(resp)
    result: list[str] = resp.json()
    return result


def secrets_remove(name: str, secret_name: str, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.delete(f"/api/v1/services/{name}/secrets/{secret_name}")
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def deploy(name: str, payload: dict[str, Any], env: str | None = None) -> dict[str, Any]:
    # Large script uploads can take well over 30s — use a generous timeout.
    client, _ = _get_client(env, timeout=300)
    resp = client.post(f"/api/v1/services/{name}/deploy", json=payload)
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def get_deployment(name: str, deployment_id: int, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.get(f"/api/v1/services/{name}/deployments/{deployment_id}")
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def query(name: str, sql: str, limit: int = 1000, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.post(f"/api/v1/services/{name}/query", json={"sql": sql, "limit": limit})
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def describe(name: str, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.get(f"/api/v1/services/{name}/describe")
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def get_logs(
    name: str, limit: int = 10, status_filter: str | None = None, env: str | None = None
) -> list[dict[str, Any]]:
    client, _ = _get_client(env)
    params: dict[str, Any] = {"limit": limit}
    if status_filter:
        params["status_filter"] = status_filter
    resp = client.get(f"/api/v1/services/{name}/logs", params=params)
    _raise_for_status(resp)
    result: list[dict[str, Any]] = resp.json()
    return result


def run_pipeline(name: str, script: str | None = None, env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    path = f"/api/v1/services/{name}/run/{script}" if script else f"/api/v1/services/{name}/run"
    resp = client.post(path)
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result


def submit_feedback(payload: dict[str, Any], env: str | None = None) -> dict[str, Any]:
    client, _ = _get_client(env)
    resp = client.post("/api/v1/feedback", json=payload)
    _raise_for_status(resp)
    result: dict[str, Any] = resp.json()
    return result
