from typing import Optional, Any, Union
from datetime import datetime, timedelta, timezone
import os

# 导入配置
from app.core.config import config_handler

# 获取配置
JWT_SECRET_KEY = config_handler.get("admin_app", "JWT_SECRET_KEY", "dev-jwt-secret-key-change-in-production")
JWT_ALGORITHM = config_handler.get("admin_app", "ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = config_handler.get_int("admin_app", "ACCESS_TOKEN_EXPIRE_MINUTES", 30)

# 修复JWT导入 - 确保使用正确的JWT库
try:
    # 首先尝试使用PyJWT
    import jwt as pyjwt
    # 测试是否有encode方法
    test_token = pyjwt.encode({"test": "data"}, "secret", algorithm="HS256")
    jwt = pyjwt
    JWT_ERROR = (pyjwt.PyJWTError, pyjwt.DecodeError, pyjwt.ExpiredSignatureError)
    print("✅ 使用PyJWT库")
except (ImportError, AttributeError, TypeError) as e:
    print(f"PyJWT导入失败: {e}")
    try:
        # 尝试使用python-jose
        from jose import jwt, JWTError
        JWT_ERROR = (JWTError,)
        print("✅ 使用python-jose库")
    except ImportError as e:
        print(f"python-jose导入失败: {e}")
        # 最后尝试安装PyJWT
        print("尝试安装PyJWT...")
        import subprocess
        import sys
        try:
            subprocess.check_call([sys.executable, "-m", "pip", "install", "PyJWT"])
            import jwt
            JWT_ERROR = (jwt.PyJWTError, jwt.DecodeError, jwt.ExpiredSignatureError)
            print("✅ PyJWT安装成功")
        except Exception as install_error:
            print(f"❌ PyJWT安装失败: {install_error}")
            raise ImportError("无法导入JWT库，请手动安装: pip install PyJWT")


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """
    创建访问令牌
    
    Args:
        data: 要编码的数据
        expires_delta: 过期时间增量
        
    Returns:
        str: JWT令牌
    """
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        # 优先使用后台管理专用的token过期时间
        admin_expire_minutes = config_handler.get_int("admin_app", "ADMIN_TOKEN_EXPIRE_MINUTES", None)
        if admin_expire_minutes is not None:
            expire = datetime.now(timezone.utc) + timedelta(minutes=admin_expire_minutes)
        else:
            expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({
        "exp": expire,
        "iat": datetime.now(timezone.utc)
    })
    
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)
    
    # PyJWT 2.0+ 返回字符串，旧版本返回bytes
    if isinstance(encoded_jwt, bytes):
        encoded_jwt = encoded_jwt.decode('utf-8')
    
    return encoded_jwt


def verify_token(token: str) -> Optional[dict]:
    """
    验证令牌
    
    Args:
        token: JWT令牌
        
    Returns:
        Optional[dict]: 解码后的payload，验证失败返回None
    """
    try:
        payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
        return payload
    except JWT_ERROR as e:
        print(f"Token验证失败: {e}")
        return None
    except Exception as e:
        print(f"Token验证异常: {e}")
        return None


def verify_and_refresh_token(token: str) -> tuple[Optional[dict], Optional[str]]:
    """
    验证令牌并实现滑动过期机制
    
    Args:
        token: JWT令牌
        
    Returns:
        tuple: (payload, new_token) - 如果需要刷新则返回新token，否则new_token为None
    """
    import logging
    logger = logging.getLogger(__name__)
    
    try:
        payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
        
        # 检查是否需要刷新token（滑动过期机制）
        exp = payload.get('exp')
        iat = payload.get('iat')
        
        if exp and iat:
            current_time = datetime.now(timezone.utc)
            exp_time = datetime.fromtimestamp(exp, tz=timezone.utc)
            iat_time = datetime.fromtimestamp(iat, tz=timezone.utc)
            # 如果需要显示本地时间
            local_iat_time = iat_time.astimezone()  # 转换为本地时区
            local_exp_time = exp_time.astimezone()  # 转换为本地时区
            
            # 获取token总有效期（分钟）
            admin_expire_minutes = config_handler.get_int("admin_app", "ADMIN_TOKEN_EXPIRE_MINUTES", None)
            total_expire_minutes = admin_expire_minutes if admin_expire_minutes is not None else ACCESS_TOKEN_EXPIRE_MINUTES
            
            # 计算token已使用时间和剩余时间
            token_age = current_time - iat_time
            token_age_seconds = token_age.total_seconds()
            token_age_minutes = token_age_seconds / 60
            
            time_remaining = exp_time - current_time
            time_remaining_seconds = time_remaining.total_seconds()
            time_remaining_minutes = time_remaining_seconds / 60

            
            
            # 获取用户名用于日志
            username = payload.get('username', 'unknown')
            
            # 打印详细的token信息日志
            logger.info(f"Token验证信息 - 用户: {username}")
            logger.info(f"  Token配置时长: {total_expire_minutes} 分钟")
            logger.info(f"  Token创建时间: {local_iat_time.strftime('%Y-%m-%d %H:%M:%S')}")
            logger.info(f"  Token过期时间: {local_exp_time.strftime('%Y-%m-%d %H:%M:%S')}")
            logger.info(f"  Token已使用时长: {token_age_minutes:.2f} 分钟 ({token_age_seconds:.0f} 秒)")
            logger.info(f"  Token剩余时长: {time_remaining_minutes:.2f} 分钟 ({time_remaining_seconds:.0f} 秒)")
            
            # 如果token使用时间超过总有效期的一半，则刷新token
            refresh_threshold_seconds = total_expire_minutes * 60 / 2
            if token_age_seconds > refresh_threshold_seconds:
                # 创建新的token数据，保持原有信息
                new_token_data = {k: v for k, v in payload.items() if k not in ['exp', 'iat']}
                new_token = create_access_token(new_token_data)
                logger.info(f"  Token刷新: 已使用时长超过阈值 ({refresh_threshold_seconds/60:.2f} 分钟)，生成新token")
                return payload, new_token
            else:
                logger.info(f"  Token刷新: 未达到刷新阈值 ({refresh_threshold_seconds/60:.2f} 分钟)，继续使用当前token")
        
        return payload, None
        
    except JWT_ERROR as e:
        logger.error(f"Token验证失败: {e}")
        return None, None
    except Exception as e:
        logger.error(f"Token验证异常: {e}")
        return None, None


def refresh_token_sliding_expiration(token: str) -> Optional[str]:
    """
    刷新token实现滑动过期
    
    Args:
        token: 当前JWT令牌
        
    Returns:
        Optional[str]: 新的JWT令牌，如果验证失败返回None
    """
    try:
        payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
        
        # 创建新的token数据，移除时间相关字段
        new_token_data = {k: v for k, v in payload.items() if k not in ['exp', 'iat']}
        
        # 创建新token
        new_token = create_access_token(new_token_data)
        return new_token
        
    except JWT_ERROR as e:
        print(f"Token刷新失败: {e}")
        return None
    except Exception as e:
        print(f"Token刷新异常: {e}")
        return None


def decode_token(token: str) -> Optional[dict]:
    """
    解码令牌（不验证签名）
    
    Args:
        token: JWT令牌
        
    Returns:
        Optional[dict]: 解码后的payload
    """
    try:
        # 不验证签名，仅解码
        payload = jwt.decode(token, options={"verify_signature": False})
        return payload
    except Exception as e:
        print(f"Token解码失败: {e}")
        return None
