# app/api/deps.py
from typing import Generator
from fastapi import Depends, HTTPException, status, WebSocket
from fastapi.security import OAuth2PasswordBearer
from jose import jwt
from pydantic import ValidationError
from sqlalchemy.orm import Session
import logging

from app.core.config import settings
from app.db.session import SessionLocal
from app.models.user import User
from app.schemas.token import TokenPayload
from app.services.user_service import UserService
from app.services.media_service import MediaService

reusable_oauth2 = OAuth2PasswordBearer(
    tokenUrl=f"{settings.API_V1_STR}/login/access-token"
)

logger = logging.getLogger(__name__)

def get_db() -> Generator:
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

def get_current_user(
    db: Session = Depends(get_db),
    token: str = Depends(reusable_oauth2)
) -> User:
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
        token_data = TokenPayload(**payload)
    except (jwt.JWTError, ValidationError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Not authenticated",
            headers={"WWW-Authenticate": "Bearer"},
        )
    user = UserService.get_user(db, user_id=token_data.sub)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return user

def get_media_service() -> MediaService:
    """
    로컬 스토리지 기반 미디어 서비스를 생성합니다.
    환경 변수에 설정된 값들을 기반으로 서비스를 구성합니다.
    """
    
    storage_path = settings.STORAGE_BASE_PATH
    base_url = settings.BASE_URL
    
    logger.info(f"Initializing MediaService with local storage path: {storage_path}")
    
    media_service = MediaService(
        storage_base_path=storage_path,
        base_url=base_url
    )
    
    return media_service

async def get_current_ws_user(
    websocket: WebSocket,
    db: Session = Depends(get_db)
) -> User:
    """
    Dependency for user authentication in WebSocket connections.
    Reads the token from query parameters, validates the JWT, and returns user information.
    """
    try:
        token = websocket.query_params.get("token")
        logger.info(f"[DEBUG] Received token for WS connection: {token[:10]}...")
        logger.info(f"[DEBUG] WebSocket request URL: {websocket.url.path}")
        logger.info(f"[DEBUG] WebSocket query params: {websocket.query_params}")

        if not token:
            logger.warning("No token provided for WS connection")
            await websocket.close(code=1008)
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not authenticated"
            )

        try:
            # Debug token validity
            from datetime import datetime
            import json
            import base64
            
            # Parse token without validation
            parts = token.split(".")
            if len(parts) == 3:
                header_b64, payload_b64, signature = parts
                padding = 4 - (len(payload_b64) % 4) if len(payload_b64) % 4 else 0
                payload_b64 += '=' * padding
                payload_b64 = payload_b64.replace('-', '+').replace('_', '/')
                
                try:
                    payload_data = json.loads(base64.b64decode(payload_b64).decode('utf-8'))
                    logger.info(f"[DEBUG] Token payload: {payload_data}")
                    
                    exp = payload_data.get("exp")
                    current_ts = datetime.now().timestamp()
                    logger.info(f"[DEBUG] JWT exp value: {exp}, current timestamp: {current_ts}")
                except Exception as e:
                    logger.error(f"[DEBUG] Error decoding token payload: {str(e)}")
            
            # Normal token validation
            logger.info(f"[DEBUG] Decoding token with SECRET_KEY: {settings.SECRET_KEY[:5]}...")
            payload = jwt.decode(
                token, 
                settings.SECRET_KEY, 
                algorithms=["HS256"]
            )
            logger.info(f"[DEBUG] Token decoded successfully: {payload}")
            token_data = TokenPayload(**payload)
        except Exception as e:
            logger.error(f"Token validation error: {str(e)}")
            await websocket.close(code=1008)
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Could not validate credentials: {str(e)}"
            )

        # Convert the sub (user id) to integer
        try:
            user_id = int(token_data.sub)
        except ValueError:
            logger.error(f"Invalid user id in token: {token_data.sub}")
            await websocket.close(code=1008)
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Invalid user id"
            )
            
        user = UserService.get_user(db, user_id=user_id)
        if not user:
            logger.warning(f"User not found for id: {user_id}")
            await websocket.close(code=1008)
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="User not found"
            )
        
        logger.info(f"WS authentication successful for user: {user.id}")
        return user
    except Exception as e:
        logger.error(f"Unexpected error in get_current_ws_user: {str(e)}")
        raise

def get_current_admin_user(
    current_user: User = Depends(get_current_user),
) -> User:
    """
    현재 로그인한 사용자가 관리자인지 확인합니다.
    관리자가 아닌 경우 403 Forbidden 오류를 발생시킵니다.
    """
    if not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="This endpoint requires admin privileges",
        )
    return current_user