from __future__ import annotations

import json
import os
import urllib.error
import urllib.request
from typing import Any, Optional

from worklib.auth_as_employer import get_access_token


DEFAULT_COMPANY_ID = "65437401ae3af6f8ffcdbaf8"
DEFAULT_GRAPHQL_URL = "https://admin.dev.dipal.ru/graphql"


def build_headers(access_token: str, *, company_id: str = DEFAULT_COMPANY_ID) -> dict[str, str]:
    return {
        "Authorization": f"Bearer {access_token}",
        "x-company-id": company_id,
    }


def execute_graphql(
    *,
    query: str,
    variables: Optional[dict[str, Any]] = None,
    graphql_url: Optional[str] = None,
    company_id: str = DEFAULT_COMPANY_ID,
    access_token: Optional[str] = None,
    timeout_s: int = 30,
) -> dict[str, Any]:
    graphql_url = graphql_url or os.getenv("GRAPHQL_URL") or DEFAULT_GRAPHQL_URL
    if not graphql_url:
        raise ValueError("Не задан GRAPHQL_URL (передайте graphql_url или установите env GRAPHQL_URL)")

    token = access_token or get_access_token()
    headers = build_headers(token, company_id=company_id)

    payload: dict[str, Any] = {"query": query}
    if variables is not None:
        payload["variables"] = variables

    req = urllib.request.Request(
        graphql_url,
        data=json.dumps(payload).encode("utf-8"),
        headers={"content-type": "application/json", **headers},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout_s) as resp:
            raw = resp.read().decode("utf-8")
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")
        raise RuntimeError(f"GraphQL HTTP {e.code}: {body}") from e

    data = json.loads(raw) if raw else {}
    if isinstance(data, dict) and data.get("errors"):
        errors = data["errors"]
        # На стенде часть операций возвращает Forbidden как GraphQL error (не HTTP 403).
        if isinstance(errors, list) and any(getattr(err, "get", lambda *_: None)("status") == 403 for err in errors):
            raise PermissionError(
                "Forbidden (403) для GraphQL операции. "
                "Проверьте креды/права. Можно задать env: AUTH_USERNAME/AUTH_PASSWORD/AUTH_GRANT_TYPE."
            )
        raise RuntimeError(f"GraphQL errors: {errors}")
    if not isinstance(data, dict):
        raise RuntimeError(f"GraphQL response is not an object: {data!r}")
    return data

