import json
import logging
import traceback
import datetime
from typing import Optional

from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel, ValidationError
from sqlalchemy import and_, update, select, or_
from sqlalchemy.ext.asyncio import AsyncSession

from app.db.session import get_db
from app.models.user_device_login import UserDeviceLogin
from app.core.security import validate_token
from app.utils.responses import custom_response
from app.core.logging import logger
import time

def now_epoch() -> int:
    """
    Returns the current time in Unix epoch format (integer).
    """
    return int(time.time())

router = APIRouter()

# --- Placeholder for the schema if a request body is needed,
# --- but for a logout API, the token and IP are sufficient.
# class LogoutRequest(BaseModel):
#     ...

# ---------- Logout API (POST) ----------
@router.post("/logout")
async def logout_user(
    request: Request,
    db: AsyncSession = Depends(get_db),
    token_data: dict = Depends(validate_token)
):
    """
    Handles user logout by updating the logout_at and logout_ip fields in the database.
    The endpoint relies on the bearer token to identify the user and their device.
    """
    logger.info("Received request for /logout endpoint.")
    try:
        # Step 1: Authorization check
        if token_data.get('code') != 200:
            logger.warning(f"Unauthorized logout attempt. Message: {token_data.get('message', 'N/A')}")
            return custom_response(code=token_data.get('code', 500), message=token_data.get('message', 'Unauthorized'))

        # Step 2: Get user and device information from the validated token
        user_id = token_data.get('user_id')
        user_device_id = token_data.get('user_device_id')
        
        logger.info(f"Processing logout for user_id: {user_id}, user_device_id: {user_device_id}")

        # Ensure at least one identifier is present in the token
        if not user_id and not user_device_id:
            logger.warning("Neither user_id nor user_device_id found in token. Cannot process logout.")
            return custom_response(code=400, message="User ID or device ID not found in token")

        # Step 3: Get the client's IP address
        logout_ip = request.client.host if request.client else None
        logger.debug(f"Client IP address for logout: {logout_ip}")
        
        # Step 4: Construct the update statement with correct logic
        # Require both user_id and user_device_id for logout
        if user_id and user_device_id:
            logger.info("Both user_id and user_device_id are present. Proceeding with database update.")
            update_stmt = (
                update(UserDeviceLogin)
                .where(and_(
                    UserDeviceLogin.user_id == user_id,
                    UserDeviceLogin.user_device_id == user_device_id
                ))
                .values(
                    logout_ip=logout_ip,
                    user_id=None,
                    logout_at=now_epoch()
                )
            )
        else:
            logger.warning("Incomplete authentication data. Both user_id and user_device_id are required for logout.")
            return custom_response(code=400, message="Both user_id and user_device_id are required for logout.")
        
        # Step 5: Execute the update statement and commit the transaction
        await db.execute(update_stmt)
        await db.commit()
        
        logger.info(f"Logout successful for user {user_id} on device {user_device_id}.")
        return custom_response(code=200, message="Logout successful")

    except Exception as e:
        await db.rollback()
        logger.error(f"Error during logout for user {user_id} and device {user_device_id}: {str(e)}", exc_info=True)
        return custom_response(code=500, message=f"Internal server error: {str(e)}")
