"""
common.py — shared auth helpers для farmOS tools.

farmOS 4.x підтримує тільки OAuth2 Bearer (не Basic Auth).
При наявності FARMOS_TOKEN — використовуємо його як статичний Bearer.
При наявності FARMOS_USER + FARMOS_PASS — отримуємо JWT через OAuth2
password grant і кешуємо його в пам'яті до закінчення TTL.
"""
import os
import time
import threading
import requests

# ── In-memory OAuth2 token cache (process-level, thread-safe) ────────────────
_token_cache: dict = {}
_token_lock = threading.Lock()

_OAUTH_TOKEN_PATH = "/oauth/token"
# Оновлюємо токен за 60 секунд до закінчення, щоб не отримати 401
_TOKEN_REFRESH_BUFFER_S = 60


def _farmos_base_url() -> str:
    return os.getenv("FARMOS_BASE_URL", "").strip().rstrip("/")


def _fetch_oauth_token(base_url: str, user: str, pwd: str, client_id: str) -> str | None:
    """
    Робить POST /oauth/token з password grant.
    Fail-closed: будь-яка помилка → повертає None (без raise).
    """
    try:
        resp = requests.post(
            base_url + _OAUTH_TOKEN_PATH,
            data={
                "grant_type": "password",
                "username": user,
                "password": pwd,
                "client_id": client_id,
                "scope": "",
            },
            timeout=5,
        )
        if resp.status_code == 200:
            data = resp.json()
            access_token = data.get("access_token", "")
            expires_in = float(data.get("expires_in", 3600))
            if access_token:
                with _token_lock:
                    _token_cache["access_token"] = access_token
                    _token_cache["expires_at"] = time.monotonic() + expires_in - _TOKEN_REFRESH_BUFFER_S
                return access_token
    except Exception:
        pass
    return None


def _get_cached_oauth_token(base_url: str, user: str, pwd: str, client_id: str) -> str | None:
    """
    Повертає кешований токен або отримує новий якщо протух / відсутній.
    """
    with _token_lock:
        cached = _token_cache.get("access_token")
        expires_at = _token_cache.get("expires_at", 0.0)
        if cached and time.monotonic() < expires_at:
            return cached

    # Поза lock — робимо мережевий запит
    return _fetch_oauth_token(base_url, user, pwd, client_id)


def _auth_headers() -> dict:
    """
    Повертає заголовки авторизації для farmOS JSON:API запитів.

    Пріоритет:
    1. FARMOS_TOKEN (статичний Bearer — для dev/тестів або PAT)
    2. FARMOS_USER + FARMOS_PASS → OAuth2 password grant → Bearer JWT
    3. Порожній dict (fail-closed: запит піде без auth, farmOS поверне 403/401)
    """
    # 1. Статичний токен
    token = os.getenv("FARMOS_TOKEN", "").strip()
    if token:
        return {"Authorization": f"Bearer {token}"}

    # 2. OAuth2 password grant
    user = os.getenv("FARMOS_USER", "").strip()
    pwd = os.getenv("FARMOS_PASS", os.getenv("FARMOS_PASSWORD", "")).strip()
    client_id = os.getenv("FARMOS_CLIENT_ID", "farm").strip()
    base_url = _farmos_base_url()

    if user and pwd and base_url:
        jwt = _get_cached_oauth_token(base_url, user, pwd, client_id)
        if jwt:
            return {"Authorization": f"Bearer {jwt}"}

    return {}
