"""
Token自动刷新中间件
实现滑动过期机制
"""
import sys
import os

# 添加src目录到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../..'))

from fastapi import Request, Response
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from app.services.jwt_token import verify_and_refresh_token
from app.core.exceptions import AuthenticationError
import logging

logger = logging.getLogger(__name__)


class TokenRefreshMiddleware(BaseHTTPMiddleware):
    """Token自动刷新中间件"""
    
    def __init__(self, app, exclude_paths: list = None):
        super().__init__(app)
        # 不需要token验证的路径
        self.exclude_paths = exclude_paths or [
            "/auth/login",
            "/auth/captcha", 
            "/auth/refresh",
            "/docs",
            "/openapi.json",
            "/redoc",
            "/favicon.ico"
        ]
    
    async def dispatch(self, request: Request, call_next):
        """处理请求"""
        
        # 检查是否是需要排除的路径
        if any(request.url.path.startswith(path) for path in self.exclude_paths):
            return await call_next(request)
        
        # 获取Authorization头
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Bearer "):
            return await call_next(request)
        
        # 提取token
        token = auth_header[7:]  # 移除 "Bearer " 前缀
        
        try:
            # 验证token并检查是否需要刷新
            payload, new_token = verify_and_refresh_token(token)
            
            if not payload:
                # Token无效，返回401错误
                logger.warning(f"无效的访问令牌，路径: {request.url.path}")
                return JSONResponse(
                    status_code=401,
                    content={
                        "code": 401,
                        "message": "无效的访问令牌",
                        "data": None
                    }
                )
            
            # 继续处理请求
            response = await call_next(request)
            
            # 如果生成了新token，在响应头中返回
            if new_token:
                response.headers["X-New-Token"] = new_token
                response.headers["X-Token-Refreshed"] = "true"
                logger.info(f"Token已刷新，用户: {payload.get('username', 'unknown')}, 路径: {request.url.path}")
            
            return response
            
        except Exception as e:
            logger.error(f"Token刷新中间件错误: {e}, 路径: {request.url.path}")
            return await call_next(request)