from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from fastapi.security import HTTPBearer
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase

from ...core.config import settings
from ...core.database import get_database
from ...core.security import (
    create_access_token,
    create_refresh_token,
    decode_token,
    verify_password,
)
from ...models.user import User, AuthProvider, UserRole
from ...schemas.auth import (
    LoginRequest,
    LoginResponse,
    LogoutResponse,
    RefreshResponse,
    MicrosoftLoginRequest,
    MicrosoftLoginResponse,
)
from ...services.microsoft_auth import (
    get_microsoft_auth_service,
    MicrosoftTokenValidationError,
    MicrosoftAuthError,
)

router = APIRouter(prefix="/auth", tags=["auth"])
security = HTTPBearer()


@router.post("/login", response_model=LoginResponse)
async def login(
    login_data: LoginRequest,
    response: Response,
):
    print(f"LOGIN: Starting login for {login_data.email}")
    # Create database connection directly (bypass dependency injection issues)
    client = AsyncIOMotorClient(settings.mongodb_uri)
    db = client[settings.mongodb_db]
    
    try:
        print("LOGIN: Database connection created")
        # Find user by email
        print("LOGIN: Looking up user in database")
        user_doc = await db.users.find_one({"email": login_data.email})
        print(f"LOGIN: User lookup complete, found: {user_doc is not None}")
        if not user_doc:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect email or password",
            )

        user = User(**user_doc)

        # Check if user uses Microsoft authentication
        if user.auth_provider == AuthProvider.MICROSOFT:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="This account uses Microsoft authentication. Please sign in with Microsoft.",
            )

        # Verify password
        if not user.hashed_password or not verify_password(login_data.password, user.hashed_password):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect email or password",
            )

        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User account is disabled",
            )

        # Create tokens
        access_token = create_access_token(subject=str(user.id))
        refresh_token = create_refresh_token(subject=str(user.id))

        # Set refresh token as HttpOnly cookie
        response.set_cookie(
            key="refresh_token",
            value=refresh_token,
            httponly=True,
            secure=settings.cookie_secure,
            samesite=settings.cookie_samesite,
            domain=settings.cookie_domain if settings.app_env == "prod" else None,
            max_age=settings.jwt_refresh_ttl_days * 24 * 60 * 60,
        )

        return LoginResponse(
            access_token=access_token,
            user_id=str(user.id),
            role=user.role,
        )
    
    finally:
        # Close database connection
        client.close()


@router.post("/microsoft", response_model=MicrosoftLoginResponse)
async def microsoft_login(
    login_data: MicrosoftLoginRequest,
    response: Response,
):
    """Authenticate user with Microsoft ID token.

    This endpoint validates the Microsoft ID token, finds or creates the user,
    and returns JWT tokens for API access.
    """
    print(f"MICROSOFT LOGIN: Starting Microsoft authentication")

    # Create database connection
    client = AsyncIOMotorClient(settings.mongodb_uri)
    db = client[settings.mongodb_db]

    try:
        # Validate Microsoft token
        microsoft_auth = get_microsoft_auth_service()
        try:
            user_info = microsoft_auth.validate_token(login_data.id_token)
            print(f"MICROSOFT LOGIN: Token validated for {user_info.email}")
        except MicrosoftTokenValidationError as e:
            print(f"MICROSOFT LOGIN ERROR: Token validation failed: {e}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail=f"Microsoft authentication failed: {str(e)}",
            )
        except MicrosoftAuthError as e:
            print(f"MICROSOFT LOGIN ERROR: Authentication error: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Microsoft authentication service error",
            )

        # Find or create user
        user_doc = await db.users.find_one({"email": user_info.email})

        if user_doc:
            # User exists
            user = User(**user_doc)
            print(f"MICROSOFT LOGIN: Existing user found: {user.id}")

            # Update auth_provider if user is switching from local to Microsoft
            if user.auth_provider == AuthProvider.LOCAL:
                print(f"MICROSOFT LOGIN: Updating user to Microsoft auth provider")
                await db.users.update_one(
                    {"_id": user_doc["_id"]},
                    {
                        "$set": {
                            "auth_provider": AuthProvider.MICROSOFT.value,
                            "updated_at": datetime.utcnow()
                        }
                    }
                )
                user.auth_provider = AuthProvider.MICROSOFT

        else:
            # Create new user
            print(f"MICROSOFT LOGIN: Creating new user for {user_info.email}")
            new_user_id = f"ms-{user_info.sub[:20]}"  # Use Microsoft sub as ID
            new_user = {
                "_id": new_user_id,
                "email": user_info.email,
                "full_name": user_info.name,
                "hashed_password": None,  # No password for Microsoft users
                "role": UserRole.PRODUCTION.value,
                "auth_provider": AuthProvider.MICROSOFT.value,
                "is_active": True,
                "created_at": datetime.utcnow(),
                "updated_at": datetime.utcnow(),
            }

            await db.users.insert_one(new_user)
            user = User(**new_user)
            print(f"MICROSOFT LOGIN: New user created: {user.id}")

        # Check if user is active
        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User account is disabled",
            )

        # Create JWT tokens
        access_token = create_access_token(subject=str(user.id))
        refresh_token = create_refresh_token(subject=str(user.id))

        # Set refresh token as HttpOnly cookie
        response.set_cookie(
            key="refresh_token",
            value=refresh_token,
            httponly=True,
            secure=settings.cookie_secure,
            samesite=settings.cookie_samesite,
            domain=settings.cookie_domain if settings.app_env == "prod" else None,
            max_age=settings.jwt_refresh_ttl_days * 24 * 60 * 60,
        )

        print(f"MICROSOFT LOGIN: Authentication successful for {user.email}")
        return MicrosoftLoginResponse(
            access_token=access_token,
            user_id=str(user.id),
            role=user.role if isinstance(user.role, str) else user.role.value,
            email=user.email,
            full_name=user.full_name,
            auth_provider=user.auth_provider,
        )

    finally:
        # Close database connection
        client.close()


@router.post("/refresh", response_model=RefreshResponse)
async def refresh_token(
    request: Request,
    response: Response,
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    refresh_token = request.cookies.get("refresh_token")
    print(f"🔍 REFRESH DEBUG: Cookie exists: {bool(refresh_token)}")

    if not refresh_token:
        print("🚨 REFRESH ERROR: No refresh token in cookies")
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Refresh token not found",
        )

    try:
        print(f"🔍 REFRESH DEBUG: Attempting to decode token...")
        payload = decode_token(refresh_token)
        print(f"🔍 REFRESH DEBUG: Token decoded successfully, type={payload.get('type')}")

        if payload.get("type") != "refresh":
            print(f"🚨 REFRESH ERROR: Wrong token type: {payload.get('type')}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid token type",
            )

        user_id = payload.get("sub")
        print(f"🔍 REFRESH DEBUG: User ID from token: {user_id}")
        if not user_id:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid token",
            )

        # Verify user still exists and is active
        user_doc = await db.users.find_one({"_id": user_id})
        if not user_doc:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found",
            )

        user = User(**user_doc)
        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User account is disabled",
            )

        # Create new tokens
        new_access_token = create_access_token(subject=user_id)
        new_refresh_token = create_refresh_token(subject=user_id)

        # Update refresh token cookie
        response.set_cookie(
            key="refresh_token",
            value=new_refresh_token,
            httponly=True,
            secure=settings.cookie_secure,
            samesite=settings.cookie_samesite,
            domain=settings.cookie_domain if settings.app_env == "prod" else None,
            max_age=settings.jwt_refresh_ttl_days * 24 * 60 * 60,
        )

        print(f"🔍 REFRESH DEBUG: Refresh successful for user {user_id}")
        return RefreshResponse(
            access_token=new_access_token,
            user_id=user_id,
            role=user.role if isinstance(user.role, str) else user.role.value,
            email=user.email,
            full_name=user.full_name
        )

    except Exception as e:
        print(f"🚨 REFRESH ERROR: Exception during refresh: {type(e).__name__}: {e}")
        import traceback
        print(f"Traceback:\n{traceback.format_exc()}")
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"Invalid refresh token: {str(e)}",
        )


@router.post("/logout", response_model=LogoutResponse)
async def logout(response: Response):
    # Clear refresh token cookie
    response.delete_cookie(
        key="refresh_token",
        httponly=True,
        secure=settings.cookie_secure,
        samesite=settings.cookie_samesite,
        domain=settings.cookie_domain if settings.app_env == "prod" else None,
    )

    return LogoutResponse()
