import logging

import requests
from django.conf import settings
from django.core.cache import cache

logger = logging.getLogger(__name__)

WX_TOKEN_CACHE_KEY = 'wx_mini_access_token'


def invalidate_weixin_mini_access_token(club_id=None):
    if club_id:
        cache.delete(f'{WX_TOKEN_CACHE_KEY}:{club_id}')
    else:
        cache.delete(WX_TOKEN_CACHE_KEY)


def get_club_mini_access_token(club_id=None, *, force_refresh=False):
    """
    按俱乐部读取 wx_appid/wx_secret 获取 access_token（多小程序上线必需）。
    xq 缺配置时回退 settings；其它俱乐部读 club 表。
    """
    from jituan.constants import CLUB_ID_DEFAULT
    from jituan.services.club_resolver import get_club_wx_credentials

    club_id = club_id or CLUB_ID_DEFAULT
    cache_key = f'{WX_TOKEN_CACHE_KEY}:{club_id}'

    if not force_refresh:
        token = cache.get(cache_key)
        if token:
            return token

    if force_refresh:
        cache.delete(cache_key)

    appid, secret, _ = get_club_wx_credentials(club_id)
    if not appid or not secret:
        logger.error('俱乐部 %s 微信配置缺失: wx_appid/wx_secret 未设置', club_id)
        return None

    token, expires_in = _fetch_stable_token(appid, secret, force_refresh)
    if not token:
        token, expires_in = _fetch_legacy_token(appid, secret)

    if token:
        ttl = max(60, int(expires_in or 7200) - 200)
        cache.set(cache_key, token, ttl)
    return token


def get_weixin_mini_access_token(*, force_refresh=False):
    """
    获取小程序 access_token。
    force_refresh=True 时清除缓存并强制向微信重新获取，避免 token 非最新导致 40001。
    优先调用 stable_token，失败时回退普通 token 接口。
    """
    if not force_refresh:
        token = cache.get(WX_TOKEN_CACHE_KEY)
        if token:
            return token

    if force_refresh:
        invalidate_weixin_mini_access_token()

    appid = getattr(settings, 'WEIXIN_APPID', '')
    secret = getattr(settings, 'WEIXIN_SECRET', '')
    if not appid or not secret:
        logger.error('微信小程序配置缺失: WEIXIN_APPID 或 WEIXIN_SECRET 未设置')
        return None

    token, expires_in = _fetch_stable_token(appid, secret, force_refresh)
    if not token:
        token, expires_in = _fetch_legacy_token(appid, secret)

    if token:
        ttl = max(60, int(expires_in or 7200) - 200)
        cache.set(WX_TOKEN_CACHE_KEY, token, ttl)
    return token


def is_weixin_token_invalid(errcode=None, errmsg=''):
    if errcode in (40001, 40014, 42001):
        return True
    msg = (errmsg or '').lower()
    return 'invalid credential' in msg or 'access_token is invalid' in msg


def _fetch_stable_token(appid, secret, force_refresh):
    url = 'https://api.weixin.qq.com/cgi-bin/stable_token'
    payload = {
        'grant_type': 'client_credential',
        'appid': appid,
        'secret': secret,
        'force_refresh': bool(force_refresh),
    }
    try:
        resp = requests.post(url, json=payload, timeout=5)
        data = resp.json()
        token = data.get('access_token')
        if token:
            logger.info('成功获取微信 stable access_token')
            return token, data.get('expires_in', 7200)
        logger.warning(
            'stable_token 获取失败 errcode=%s errmsg=%s',
            data.get('errcode'), data.get('errmsg'),
        )
    except Exception as e:
        logger.warning('请求 stable_token 异常: %s', e)
    return None, None


def _fetch_legacy_token(appid, secret):
    url = 'https://api.weixin.qq.com/cgi-bin/token'
    params = {
        'grant_type': 'client_credential',
        'appid': appid,
        'secret': secret,
    }
    try:
        resp = requests.get(url, params=params, timeout=5)
        data = resp.json()
        token = data.get('access_token')
        if token:
            logger.info('成功获取微信 access_token (legacy)')
            return token, data.get('expires_in', 7200)
        logger.error('legacy token 获取失败: %s', data)
    except Exception as e:
        logger.error('请求 legacy token 异常: %s', e)
    return None, None
