"""SSO 服务端 HTTP 交互层（内部模块）。"""

from __future__ import annotations

import os
import time

import requests

POLL_INTERVAL = 2
POLL_TIMEOUT = 300


def _get_api_base(service_url: str) -> str:
    """探测 SSO API base URL，自动识别开发环境的 /{username}/ 路径前缀。"""
    try:
        import pwd
        pw_name = pwd.getpwuid(os.getuid()).pw_name
    except Exception:
        pw_name = None

    usernames: list[str] = []
    for src in [
        os.environ.get("USER"),
        os.path.expanduser("~").split("/")[-1],
        pw_name,
    ]:
        if src and src not in usernames:
            usernames.append(src)

    candidates = [f"/{u}/api/sso/health" for u in usernames] + ["/api/sso/health"]

    for path in candidates:
        try:
            r = requests.get(f"{service_url}{path}", timeout=3)
            if r.status_code == 200:
                prefix = path.split("/api")[0]
                return f"{service_url}{prefix}/api/sso"
        except Exception:
            continue

    return f"{service_url}/api/sso"


def verify_token(service_url: str, token: str) -> dict | None:
    """向服务端验证 token 有效性。

    Args:
        service_url: SSO 服务根 URL。
        token: 待验证的 token 字符串。

    Returns:
        token 有效时返回 user_info 字典，无效或网络错误时返回 None。
    """
    try:
        api_base = _get_api_base(service_url)
        resp = requests.post(
            f"{api_base}/verify",
            headers={"Authorization": f"Bearer {token}"},
            timeout=10,
        )
        if resp.status_code == 200:
            data = resp.json()
            if data.get("valid"):
                return data.get("user_info")
        return None
    except Exception:
        return None


def create_session(api_base: str) -> str:
    """在服务端创建轮询 session，返回 session_id。"""
    resp = requests.post(f"{api_base}/session/create", timeout=10)
    resp.raise_for_status()
    return resp.json()["session_id"]


def get_login_url(api_base: str, session_id: str) -> str:
    """获取浏览器 SSO 登录 URL。"""
    resp = requests.get(
        f"{api_base}/login", params={"session_id": session_id}, timeout=10
    )
    resp.raise_for_status()
    return resp.json()["login_url"]


def poll_until_ready(
    api_base: str,
    session_id: str,
    poll_interval: int = POLL_INTERVAL,
    poll_timeout: int = POLL_TIMEOUT,
) -> dict:
    """轮询服务端直到认证完成，返回包含 token 和 user_info 的数据字典。

    Raises:
        RuntimeError: session 过期或超时。
        requests.HTTPError: 轮询请求失败。
    """
    deadline = time.time() + poll_timeout
    while time.time() < deadline:
        resp = requests.get(f"{api_base}/session/{session_id}/poll", timeout=10)
        if resp.status_code in (404, 410):
            raise RuntimeError("Session 已过期，请重新登录")
        resp.raise_for_status()
        body = resp.json()
        if body.get("status") == "ready":
            return body["data"]
        time.sleep(poll_interval)
    raise RuntimeError(f"SSO 超时（{poll_timeout} 秒内未完成认证）")
