from fastapi import APIRouter, Depends, HTTPException, status, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
import sys
import logging

# Add shared modules to path
sys.path.append('/app')

from app.schemas.auth import (
    LoginRequest, LoginResponse, RegisterRequest, RegisterResponse,
    RefreshTokenRequest, TokenResponse, PasswordResetRequest,
    PasswordResetConfirm, ChangePasswordRequest, LogoutRequest,
    VerifyEmailRequest, ResendVerificationRequest
)
from app.services.auth_service import AuthService
from app.core.dependencies import get_current_active_user
from app.models.user import User

router = APIRouter(prefix="/auth", tags=["Authentication"])
limiter = Limiter(key_func=get_remote_address)
security = HTTPBearer()

@router.post("/register", response_model=RegisterResponse)
@limiter.limit("5/minute")
async def register(request: Request, register_data: RegisterRequest):
    """Register a new user"""
    try:
        user, verification_token = await AuthService.register_user(register_data)
        
        # In production, send verification email instead of returning token
        # For demo purposes, we're returning the token
        
        return RegisterResponse(
            message="User registered successfully. Please check your email for verification.",
            user_id=str(user.id),
            email=user.email,
            username=user.username
            
        )
        
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Registration failed"
        )

@router.post("/login", response_model=LoginResponse)
@limiter.limit("10/minute")
async def login(request: Request, login_data: LoginRequest):
    """Authenticate user and return tokens"""
    try:
        # Get client info
        client_ip = get_remote_address(request)
        user_agent = request.headers.get("user-agent", "")
        
        auth_result = await AuthService.authenticate_user(
            login_data, client_ip, user_agent
        )
        
        return LoginResponse(**auth_result)
        
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e)
        )
    except Exception as e:
        # Log full exception details for debugging
        logger = logging.getLogger("auth_service")
        try:
            logger.error(
                f"Login failed for email={getattr(login_data, 'email', 'unknown')} from ip={get_remote_address(request)}",
                exc_info=True
            )
        except Exception:
            # Fallback logging if any attribute access fails
            logger.error("Login failed with unexpected error", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Login failed"
        )

@router.post("/refresh", response_model=TokenResponse)
@limiter.limit("20/minute")
async def refresh_token(request: Request, refresh_data: RefreshTokenRequest):
    """Refresh access token"""
    try:
        result = await AuthService.refresh_access_token(refresh_data.refresh_token)
        return TokenResponse(**result)
        
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e)
        )
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Token refresh failed"
        )

@router.post("/logout")
@limiter.limit("20/minute")
async def logout(
    request: Request,
    logout_data: LogoutRequest,
    current_user: User = Depends(get_current_active_user)
):
    """Logout user"""
    try:
        await AuthService.logout_user(
            str(current_user.id),
            logout_data.refresh_token,
            logout_data.logout_all_devices
        )
        
        # Blacklist current access token
        auth_header = request.headers.get("authorization", "")
        if auth_header.startswith("Bearer "):
            from app.services.token_service import TokenService
            token = auth_header.split(" ")[1]
            await TokenService.blacklist_token(token, "logout")
        
        return {"message": "Logged out successfully"}
        
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Logout failed"
        )

@router.post("/verify-email")
@limiter.limit("10/minute")
async def verify_email(request: Request, verify_data: VerifyEmailRequest):
    """Verify user email"""
    try:
        success = await AuthService.verify_email(verify_data.token)
        
        if success:
            return {"message": "Email verified successfully"}
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Email verification failed"
            )
            
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Email verification failed"
        )

@router.post("/resend-verification")
@limiter.limit("3/minute")
async def resend_verification(request: Request, resend_data: ResendVerificationRequest):
    """Resend email verification"""
    try:
        # This would typically generate a new verification token
        # and send an email. For demo purposes, we'll just return success
        return {"message": "Verification email sent"}
        
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to send verification email"
        )

@router.post("/forgot-password")
@limiter.limit("3/minute")
async def forgot_password(request: Request, reset_data: PasswordResetRequest):
    """Request password reset"""
    try:
        result = await AuthService.request_password_reset(reset_data.email)
        
        # Always return the same message to prevent email enumeration
        return {"message": "If the email exists, a reset link has been sent"}
        
    except Exception:
        return {"message": "If the email exists, a reset link has been sent"}

@router.post("/reset-password")
@limiter.limit("10/minute")
async def reset_password(request: Request, reset_data: PasswordResetConfirm):
    """Reset password with token"""
    try:
        success = await AuthService.reset_password(
            reset_data.token,
            reset_data.new_password
        )
        
        if success:
            return {"message": "Password reset successfully"}
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password reset failed"
            )
            
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Password reset failed"
        )

@router.post("/change-password")
@limiter.limit("10/minute")
async def change_password(
    request: Request,
    change_data: ChangePasswordRequest,
    current_user: User = Depends(get_current_active_user)
):
    """Change user password"""
    try:
        success = await AuthService.change_password(
            str(current_user.id),
            change_data.current_password,
            change_data.new_password
        )
        
        if success:
            return {"message": "Password changed successfully"}
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password change failed"
            )
            
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Password change failed"
        )

@router.get("/me")
async def get_current_user_info(request: Request, current_user: User = Depends(get_current_active_user)):
    """Get current user information"""
    # Get user roles from account service
    roles = []
    try:
        from shared.http_client import http_client
        from shared.config import settings
        
        # Call account service to get user roles using a valid access token
        # When reaching this endpoint, the incoming Authorization header contains a bearer access token
        # We will forward that token to the account service
        auth_header = request.headers.get("authorization", "")
        token_to_forward = auth_header.split(" ")[1] if auth_header.startswith("Bearer ") else None
        headers = {"Authorization": f"Bearer {token_to_forward}"} if token_to_forward else {}
        response = await http_client.get(
            f"{settings.account_service_url}/accounts/me",
            headers=headers
        )
        
        if response.status_code == 200:
            user_data = await response.json()
            # Extract roles from the response if available
            if "roles" in user_data:
                roles = user_data["roles"]
                print(f"Successfully fetched roles for user {current_user.username}: {roles}")
        else:
            print(f"Failed to fetch roles for user {current_user.username}: HTTP {response.status_code}")
    except Exception as e:
        # Log error but don't fail the request
        import logging
        logger = logging.getLogger("auth_service")
        logger.warning(f"Failed to fetch user roles for user {current_user.username}: {e}")
        print(f"Warning: Could not fetch roles for user {current_user.username}, using default role")
    
    # If no roles were fetched, provide a default role
    if not roles:
        roles = ["user"]  # Default role for all users
        print(f"Using default role 'user' for {current_user.username}")
    
    return {
        "user_id": str(current_user.id),
        "email": current_user.email,
        "username": current_user.username,
        "status": current_user.status.value,
        "email_verified": current_user.email_verified,
        "created_at": current_user.created_at,
        "last_successful_login": current_user.last_successful_login,
        "roles": roles
    }

@router.get("/health")
async def health_check():
    """Health check endpoint"""
    return {"status": "healthy", "service": "auth-service"}
