from __future__ import annotations

import base64
import os
from typing import Any, Dict, Optional

import requests

DEFAULT_ORG = "default"


def resolve_otlp_endpoint(default: str = "", *, endpoint: Optional[str] = None) -> str:
    """Resolve the OTLP endpoint for OpenObserve.

    When *endpoint* is supplied (e.g. already resolved by
    ``HighlighterRuntimeConfig``), it is returned directly.  Otherwise
    the function falls back to standard OTLP env vars and then to the
    OpenObserve-specific ``OPENOBSERVE_HOST`` construction.
    """
    if endpoint:
        return endpoint
    from_env = os.environ.get("HL_TELEMETRY_OTLP_ENDPOINT") or os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
    if from_env:
        return from_env
    host = os.environ.get("OPENOBSERVE_HOST")
    if host:
        org = os.environ.get("OPENOBSERVE_ORG", DEFAULT_ORG)
        return f"{host.rstrip('/')}/api/{org}/otlp"
    return default


def resolve_api_endpoint(otlp_endpoint: str, *, host: Optional[str] = None, org: Optional[str] = None) -> str:
    host = host or os.environ.get("OPENOBSERVE_HOST")
    org = org or os.environ.get("OPENOBSERVE_ORG", DEFAULT_ORG)
    if host:
        return f"{host.rstrip('/')}/api/{org}"
    base = otlp_endpoint.rstrip("/")
    if not base:
        return ""
    for suffix in ("/v1/traces", "/v1/metrics", "/v1/logs"):
        if base.endswith(suffix):
            base = base[: -len(suffix)]
            break
    if base.endswith("/v1"):
        base = base[: -len("/v1")]
    if base.endswith("/otlp"):
        base = base[: -len("/otlp")]
    return base


def basic_auth_header(user: str, password: str) -> str:
    token = base64.b64encode(f"{user}:{password}".encode("utf-8")).decode("ascii")
    return f"Basic {token}"


def basic_auth_headers(user: str, password: str) -> Dict[str, str]:
    return {"Authorization": basic_auth_header(user, password)}


def resolve_auth_headers(
    headers: Optional[Dict[str, str]] = None,
    *,
    user: Optional[str] = None,
    password: Optional[str] = None,
) -> Dict[str, str]:
    resolved = dict(headers or {})
    if not _has_header(resolved, "Authorization"):
        user = user or os.environ.get("OPENOBSERVE_USER")
        password = password or os.environ.get("OPENOBSERVE_PASSWORD")
        if user and password:
            resolved["Authorization"] = basic_auth_header(user, password)
    return resolved


def _has_header(headers: Dict[str, str], name: str) -> bool:
    needle = name.lower()
    return any(key.lower() == needle for key in headers)


class OpenObserveClient:
    def __init__(self, api_endpoint: str, *, headers: Optional[Dict[str, str]] = None, timeout: float = 30.0):
        self._api_endpoint = api_endpoint.rstrip("/")
        self._headers = dict(headers or {})
        self._timeout = timeout
        self._session = requests.Session()

    @classmethod
    def from_otlp_endpoint(
        cls,
        otlp_endpoint: str,
        *,
        headers: Optional[Dict[str, str]] = None,
        host: Optional[str] = None,
        org: Optional[str] = None,
        timeout: float = 30.0,
    ) -> "OpenObserveClient":
        api_endpoint = resolve_api_endpoint(otlp_endpoint, host=host, org=org)
        if not api_endpoint:
            raise ValueError(
                "Missing OpenObserve API endpoint. Set OPENOBSERVE_HOST or provide otlp endpoint."
            )
        return cls(api_endpoint, headers=headers, timeout=timeout)

    @property
    def api_endpoint(self) -> str:
        return self._api_endpoint

    @property
    def headers(self) -> Dict[str, str]:
        return dict(self._headers)

    def create_dashboard(self, dashboard: Dict[str, Any]) -> requests.Response:
        url = f"{self._api_endpoint}/dashboards"
        return self._session.post(url, json=dashboard, headers=self._headers, timeout=self._timeout)

    def query_metrics(
        self,
        *,
        sql: str,
        start_time_us: int,
        end_time_us: int,
        size: int = 5,
        offset: int = 0,
        timeout: int = 0,
        search_type: str = "ui",
    ) -> Dict[str, Any]:
        payload = {
            "query": {
                "sql": sql,
                "start_time": start_time_us,
                "end_time": end_time_us,
                "from": offset,
                "size": size,
            },
            "search_type": search_type,
            "timeout": timeout,
        }
        url = f"{self._api_endpoint}/_search?type=metrics"
        response = self._session.post(url, json=payload, headers=self._headers, timeout=self._timeout)
        if response.status_code >= 400:
            return {"error": f"HTTP {response.status_code}", "body": response.text}
        return response.json()
