"""
Authentication router for login, logout, and token management
"""
from fastapi import APIRouter, Depends, status, Request
from fastapi.responses import JSONResponse
from sqlalchemy.ext.asyncio import AsyncSession
import structlog

from models import get_db
from schemas.auth import (
    LoginRequest,
    TokenResponse,
    LogoutResponse,
    RefreshTokenRequest,
    UserInfo
)
from services.auth_service import AuthService
from middleware.auth_middleware import (
    get_current_user,
    get_client_ip,
    get_user_agent,
    require_viewer
)
from models.user import User

logger = structlog.get_logger()

router = APIRouter(
    prefix="/api/v1/auth",
    tags=["authentication"]
)


@router.post(
    "/login",
    response_model=TokenResponse,
    status_code=status.HTTP_200_OK,
    summary="User login",
    description="Authenticate with username and password to receive JWT tokens"
)
async def login(
    request: Request,
    credentials: LoginRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    Authenticate user and return access and refresh tokens

    **Request Body:**
    - `username`: User's username
    - `password`: User's password

    **Response:**
    - `access_token`: JWT access token (short-lived)
    - `refresh_token`: JWT refresh token (long-lived)
    - `token_type`: Token type (always "bearer")
    - `expires_in`: Access token expiration in seconds
    - `user`: Authenticated user information

    **Audit Log:**
    - Creates audit log entry for login attempt (success or failure)
    """
    auth_service = AuthService(db)

    # Get client IP and user agent for audit logging
    ip_address = get_client_ip(request)
    user_agent = get_user_agent(request)

    # Attempt login
    result = await auth_service.login(
        username=credentials.username,
        password=credentials.password,
        ip_address=ip_address,
        user_agent=user_agent
    )

    if not result:
        logger.warning("login_endpoint_failed",
                      username=credentials.username,
                      ip=ip_address)
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Invalid username or password"
            }
        )

    logger.info("login_endpoint_success",
               username=credentials.username,
               user_id=result["user"]["id"],
               ip=ip_address)

    return result


@router.post(
    "/logout",
    response_model=LogoutResponse,
    status_code=status.HTTP_200_OK,
    summary="User logout",
    description="Logout by blacklisting the current access token",
    dependencies=[Depends(require_viewer)]  # Requires authentication
)
async def logout(
    request: Request,
    db: AsyncSession = Depends(get_db)
):
    """
    Logout user by blacklisting their access token

    **Authentication Required:**
    - Must include valid JWT access token in Authorization header

    **Response:**
    - `message`: Logout confirmation message

    **Audit Log:**
    - Creates audit log entry for logout
    """
    # Extract token from Authorization header
    auth_header = request.headers.get("Authorization")
    if not auth_header:
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Authentication required"
            }
        )

    # Extract token (remove "Bearer " prefix)
    token = auth_header.split()[1] if len(auth_header.split()) == 2 else None
    if not token:
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Invalid authorization header"
            }
        )

    auth_service = AuthService(db)

    # Get client IP and user agent for audit logging
    ip_address = get_client_ip(request)
    user_agent = get_user_agent(request)

    # Perform logout
    success = await auth_service.logout(
        token=token,
        ip_address=ip_address,
        user_agent=user_agent
    )

    if not success:
        logger.warning("logout_endpoint_failed", ip=ip_address)
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Invalid or expired token"
            }
        )

    user = get_current_user(request)
    logger.info("logout_endpoint_success",
               user_id=str(user.id) if user else None,
               username=user.username if user else None,
               ip=ip_address)

    return {"message": "Successfully logged out"}


@router.post(
    "/refresh",
    status_code=status.HTTP_200_OK,
    summary="Refresh access token",
    description="Generate new access token using refresh token"
)
async def refresh_token(
    request: Request,
    refresh_request: RefreshTokenRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    Generate new access token from refresh token

    **Request Body:**
    - `refresh_token`: Valid JWT refresh token

    **Response:**
    - `access_token`: New JWT access token
    - `token_type`: Token type (always "bearer")
    - `expires_in`: Access token expiration in seconds

    **Note:**
    - Refresh token is NOT rotated (same refresh token can be reused)
    - For security, consider implementing refresh token rotation in production
    """
    auth_service = AuthService(db)

    # Get client IP for logging
    ip_address = get_client_ip(request)

    # Refresh token
    result = await auth_service.refresh_access_token(
        refresh_token=refresh_request.refresh_token,
        ip_address=ip_address
    )

    if not result:
        logger.warning("refresh_endpoint_failed", ip=ip_address)
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Invalid or expired refresh token"
            }
        )

    logger.info("refresh_endpoint_success", ip=ip_address)

    return result


@router.get(
    "/me",
    response_model=UserInfo,
    status_code=status.HTTP_200_OK,
    summary="Get current user",
    description="Get information about the currently authenticated user",
    dependencies=[Depends(require_viewer)]  # Requires authentication
)
async def get_me(request: Request):
    """
    Get current authenticated user information

    **Authentication Required:**
    - Must include valid JWT access token in Authorization header

    **Response:**
    - User information (id, username, role, created_at, updated_at)

    **Note:**
    - Password hash is NEVER included in response
    """
    user = get_current_user(request)

    if not user:
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content={
                "error": "Unauthorized",
                "message": "Authentication required"
            }
        )

    logger.info("get_me_endpoint",
               user_id=str(user.id),
               username=user.username)

    return {
        "id": str(user.id),
        "username": user.username,
        "role": user.role.value,
        "created_at": user.created_at,
        "updated_at": user.updated_at
    }
