from typing import Any, Dict, List, Optional, Tuple, Union

from fastapi import HTTPException, status
from sqlalchemy.orm import Session

from src.database.models.users import User
from src.modules.users.repositories.user import user_repository
from src.modules.users.schemas.requests import UserCreateSchema, UserUpdateSchema
from src.modules.users.schemas.responses import UserResponseSchema


async def list_users(
    db: Session,
    skip: int,
    limit: int,
    fields: str = None,
    sort_by: List[str] = ["-created_at"],
    search: Optional[str] = None,
    paginate: bool = False,
    pagination_url: str = "",
) -> Dict:
    users = await user_repository.get_list(
        db=db,
        skip=skip,
        limit=limit,
        sort_by=sort_by,
        search=search,
        paginate=paginate,
        pagination_url=pagination_url,
        use_orm=True,
    )
    return users


async def create_user(db: Session, payload: UserCreateSchema) -> UserResponseSchema:
    user = await user_repository.create_user(db=db, payload=payload)
    if user:
        return user
    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST, detail="Failed to create user"
    )


async def get_user_by_id(db: Session, user_id: int) -> UserResponseSchema:
    user, msg = user_repository.get(db=db, _id=user_id)
    if user:
        return user
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=msg)


async def get_user_by_email(db: Session, email: str) -> UserResponseSchema:
    user, msg = user_repository.get_by_name(db=db, name_in=email)
    if user:
        return user
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=msg)


async def update_user(
    db: Session, user_id: int, payload: UserUpdateSchema
) -> UserResponseSchema:
    user = user_repository.get_raw(db=db, _id=user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
        )
    updated_user = user_repository.update_by_id(
        db=db, object_id=user_id, payload=payload
    )
    if updated_user:
        return updated_user
    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST, detail="Failed to update user"
    )


async def delete_user(db: Session, user_id: int) -> Dict[str, str]:
    user = user_repository.remove(db=db, _id=user_id)
    if user:
        return {"detail": "User deleted"}
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
