#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
橘喵 jm-devops 后端客户端。

鉴权：设备密钥授权（grant_type=client_secret，免验证码）。
  先用 CLIENT_ID + CLIENT_SECRET 调 POST /auth/login 换 token（缓存于进程内，按有效期提前刷新），
  再带 Authorization: Bearer <token> + clientid 头调统计接口；遇 401 清 token 重登一次重试。

接口：
  - GET /system/statistics/realtime         今日经营实时数据
  - GET /system/statistics/recent-days?days  近 N 天每日数据（按日期降序、不含今天）
"""
import json
import time
import urllib.request
import urllib.error

import config

# 进程内 token 缓存（cron 每次独立进程，不落盘；单次运行内复用）
_token = None
_token_expire_at = 0.0
# token 到期前提前刷新的余量（秒）
_TOKEN_REFRESH_SKEW = 60


def _login():
    """用 client_secret 授权换取 token，写入模块级缓存。"""
    global _token, _token_expire_at
    # 设备专用明文登录端点（不走 @ApiEncrypt，仅放行 client_secret 授权）
    url = config.BASE_API + "/auth/deviceLogin"
    payload = json.dumps({
        "clientId": config.CLIENT_ID,
        "grantType": config.GRANT_TYPE,
        "clientSecret": config.CLIENT_SECRET,
        "tenantId": config.TENANT_ID,
    }).encode("utf-8")
    headers = {"Content-Type": "application/json;charset=utf-8", "clientid": config.CLIENT_ID}
    req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        raise RuntimeError(f"登录 HTTP {e.code}: {e.read().decode('utf-8', 'ignore')[:200]}") from e
    if data.get("code") != 200:
        raise RuntimeError(f"/auth/login 返回 code={data.get('code')}: {data.get('msg')}")
    body = data["data"]
    _token = body["access_token"]
    # expire_in 为秒；提前 skew 刷新，缺省给个保守值
    expire_in = body.get("expire_in") or 1800
    _token_expire_at = time.time() + max(0, expire_in - _TOKEN_REFRESH_SKEW)
    return _token


def _ensure_token():
    if _token and time.time() < _token_expire_at:
        return _token
    return _login()


def _get(path, _retry=True):
    global _token, _token_expire_at
    token = _ensure_token()
    url = config.BASE_API + path
    headers = {
        "Content-Type": "application/json;charset=utf-8",
        "clientid": config.CLIENT_ID,
        "Authorization": f"Bearer {token}",
    }
    req = urllib.request.Request(url, headers=headers, method="GET")
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        # token 失效（401）则清缓存重登一次重试
        if e.code == 401 and _retry:
            _token, _token_expire_at = None, 0.0
            return _get(path, _retry=False)
        raise RuntimeError(f"HTTP {e.code}: {e.read().decode('utf-8', 'ignore')[:200]}") from e
    # 业务层也可能用 401 表示未登录
    if data.get("code") == 401 and _retry:
        _token, _token_expire_at = None, 0.0
        return _get(path, _retry=False)
    if data.get("code") != 200:
        raise RuntimeError(f"{path} 返回 code={data.get('code')}: {data.get('msg')}")
    return data["data"]


def get_realtime() -> dict:
    """今日经营实时数据（单量/流水/毛利 + 环比/同比）。"""
    return _get("/system/statistics/realtime")


def get_recent_days(days=30) -> list:
    """近 N 天每日经营数据（API 按日期降序、不含今天）。"""
    return _get(f"/system/statistics/recent-days?days={days}")["days"]


if __name__ == "__main__":
    print("realtime:", json.dumps(get_realtime(), ensure_ascii=False)[:300])
    print("recent[0]:", json.dumps(get_recent_days(30)[0], ensure_ascii=False))
