"""
微信API服务
提供微信小程序和公众号相关的API调用功能
"""

import requests
import json
import logging
from typing import Optional, Dict, Any, Tuple
from .wechat_config import get_wechat_config, get_error_message, validate_wechat_config

logger = logging.getLogger(__name__)


class WechatApiService:
    """
    微信API服务类
    提供微信相关API的调用功能
    """
    
    def __init__(self, platform: str = 'miniprogram'):
        """
        初始化微信API服务
        
        Args:
            platform (str): 微信平台类型，'miniprogram' 或 'official_account'
        """
        self.platform = platform
        self.config = get_wechat_config(platform)
        
        # 验证配置
        if not validate_wechat_config(platform):
            logger.warning(f"微信{platform}配置不完整，请检查环境变量")
    
    def code_to_openid(self, code: str) -> Tuple[bool, Optional[str], Optional[str]]:
        """
        使用微信授权码换取用户openid
        
        Args:
            code (str): 微信授权码（有效期15分钟）
            
        Returns:
            Tuple[bool, Optional[str], Optional[str]]: 
            (是否成功, openid, 错误信息)
        """
        try:
            # 验证配置
            if not validate_wechat_config(self.platform):
                return False, None, "微信API配置不完整"
            
            # 构建请求参数
            if self.platform == 'miniprogram':
                params = {
                    'appid': self.config['app_id'],
                    'secret': self.config['app_secret'],
                    'js_code': code,
                    'grant_type': self.config['grant_type']
                }
                url = self.config['code2session_url']
            else:  # official_account
                params = {
                    'appid': self.config['app_id'],
                    'secret': self.config['app_secret'],
                    'code': code,
                    'grant_type': self.config['grant_type']
                }
                url = self.config['oauth2_url']
            
            # 记录请求日志
            logger.info(f"请求微信API获取openid，平台: {self.platform}")
            
            # 发起API请求
            response = requests.get(
                url,
                params=params,
                timeout=self.config['timeout']
            )
            
            if response.status_code != 200:
                error_msg = f"微信API请求失败，HTTP状态码: {response.status_code}"
                logger.error(error_msg)
                return False, None, error_msg
            
            # 解析响应
            result = response.json()
            logger.debug(f"微信API响应: {json.dumps(result, ensure_ascii=False)}")
            
            # 检查是否有错误
            if 'errcode' in result:
                error_code = result['errcode']
                if error_code != 0:
                    error_msg = get_error_message(error_code)
                    logger.error(f"微信API返回错误: {error_code} - {error_msg}")
                    return False, None, error_msg
            
            # 获取openid
            openid = result.get('openid')
            if not openid:
                error_msg = "微信API返回数据中缺少openid"
                logger.error(error_msg)
                return False, None, error_msg
            
            logger.info(f"成功获取openid: {openid}")
            return True, openid, None
            
        except requests.exceptions.Timeout:
            error_msg = "微信API请求超时"
            logger.error(error_msg)
            return False, None, error_msg
            
        except requests.exceptions.RequestException as e:
            error_msg = f"微信API请求异常: {str(e)}"
            logger.error(error_msg)
            return False, None, error_msg
            
        except json.JSONDecodeError as e:
            error_msg = f"微信API响应解析失败: {str(e)}"
            logger.error(error_msg)
            return False, None, error_msg
            
        except Exception as e:
            error_msg = f"获取openid时发生未知错误: {str(e)}"
            logger.error(error_msg, exc_info=True)
            return False, None, error_msg
    
    def code_to_openid_with_retry(self, code: str, max_retries: Optional[int] = None) -> Tuple[bool, Optional[str], Optional[str]]:
        """
        带重试机制的openid获取
        
        Args:
            code (str): 微信授权码
            max_retries (int, optional): 最大重试次数，默认使用配置中的值
            
        Returns:
            Tuple[bool, Optional[str], Optional[str]]: 
            (是否成功, openid, 错误信息)
        """
        if max_retries is None:
            max_retries = self.config.get('max_retries', 3) or 3
        
        retry_delay = self.config.get('retry_delay', 1)
        
        # 确保 max_retries 是整数
        assert isinstance(max_retries, int)
        
        for attempt in range(max_retries + 1):
            success, openid, error_msg = self.code_to_openid(code)
            
            if success:
                return True, openid, None
            
            # 如果是最后一次尝试，直接返回错误
            if attempt == max_retries:
                return False, None, error_msg
            
            # 某些错误不需要重试
            if error_msg and any(keyword in error_msg for keyword in ['无效', 'invalid', '配置不完整']):
                return False, None, error_msg
            
            # 等待后重试
            logger.warning(f"第{attempt + 1}次获取openid失败，{retry_delay}秒后重试: {error_msg}")
            import time
            time.sleep(retry_delay)
        
        return False, None, "重试次数已用尽"


# 便捷函数
def get_openid_from_code(code: str, platform: str = 'miniprogram') -> Tuple[bool, Optional[str], Optional[str]]:
    """
    从微信授权码获取openid的便捷函数
    
    Args:
        code (str): 微信授权码
        platform (str): 微信平台类型，默认为小程序
        
    Returns:
        Tuple[bool, Optional[str], Optional[str]]: 
        (是否成功, openid, 错误信息)
    """
    service = WechatApiService(platform)
    return service.code_to_openid_with_retry(code)


def validate_openid(openid: str) -> bool:
    """
    验证openid格式是否正确
    
    Args:
        openid (str): 微信用户openid
        
    Returns:
        bool: 格式是否正确
    """
    if not openid or not isinstance(openid, str):
        return False
    
    # 微信openid通常是28位字符串，由字母和数字组成
    if len(openid) != 28:
        return False
    
    # 检查是否只包含字母、数字、下划线和短横线
    import re
    pattern = r'^[a-zA-Z0-9_-]+$'
    return bool(re.match(pattern, openid))


# 导出主要类和函数
__all__ = [
    'WechatApiService',
    'get_openid_from_code',
    'validate_openid'
]
