from uuid import UUID
from fastapi import APIRouter, HTTPException
from fastapi.params import Depends
from sqlalchemy.orm import Session as DbSession

from app.database import get_db
from app.schemas.session import Session
from app.schemas.auth_token import AccessToken
from app.schemas.user import PasswordUpdate, UserUpdate, User
from app.security.jwt_bearer import JWTBearer
from app.services import session_service, user_service
from app.util.errors import InvalidStateError, NotFoundError

router = APIRouter(prefix="/me", tags=["Me (v1)"])


@router.get(path="", response_model=User)
async def get_myself(
    db: DbSession = Depends(get_db), token: AccessToken = Depends(JWTBearer())
):
    """
    Get the currently authenticated user.
    """
    user = await user_service.get_user(db=db, id=UUID(token.subject))
    if not user:
        raise HTTPException(status_code=404, detail="user_not_found")
    else:
        return user


@router.patch(path="", response_model=User)
async def update_myself(
    user_update: UserUpdate,
    db: DbSession = Depends(get_db),
    token: AccessToken = Depends(JWTBearer()),
):
    """
    Update the currently authenticated user. Changing the email address automatically marks it as not verified
    and starts a new verification workflow.
    """
    try:
        return await user_service.update_user(
            db, UUID(token.subject), user_update
        )
    except NotFoundError:
        raise HTTPException(status_code=404, detail="user_not_found")


@router.post(path="/password", response_model=list[None])
async def change_password(
    update: PasswordUpdate,
    db: DbSession = Depends(get_db),
    token: AccessToken = Depends(JWTBearer()),
):
    """
    Change the password of the currently authenticated user.
    """
    try:
        await user_service.change_user_password(
            db=db, id=UUID(token.subject), update=update
        )
        return list()
    except NotFoundError:
        raise HTTPException(status_code=404, detail="user_not_found")
    except InvalidStateError:
        raise HTTPException(status_code=409, detail="incorrect_password")


@router.get(path="/sessions", response_model=list[Session])
async def get_user_sessions(
    db: DbSession = Depends(get_db), token: AccessToken = Depends(JWTBearer())
):
    """
    List the active sessions of the currently authenticated user.
    """
    return await session_service.get_sessions_by_user(
        db=db, user_id=UUID(token.subject)
    )


@router.delete(path="/sessions", response_model=list[None])
async def clear_user_sessions(
    db: DbSession = Depends(get_db), token: AccessToken = Depends(JWTBearer())
):
    """
    Clear all sessions of the currently authenticated user.
    """
    await session_service.remove_all_sessions_for_user(
        db=db, user_id=UUID(token.subject),
    )
    return list()


@router.delete(path="/sessions/{session_id}", response_model=list[None])
async def delete_user_session(
    session_id: UUID,
    db: DbSession = Depends(get_db),
    token: AccessToken = Depends(JWTBearer()),
):
    """
    Invalidate a specific session of the currently authenticated user.
    """
    try:
        await session_service.remove_session_for_user(
            db=db,
            id=session_id,
            user_id=UUID(token.subject),
        )
    except NotFoundError:
        raise HTTPException(status_code=404, detail="session_not_found")
    return list()