import uuid
import bcrypt
from fastapi import APIRouter, Request

from fastapi.responses import JSONResponse

from ..utils import MONGODB_DATABASE, mongodb_connect, check_access, get_user_sub, get_roles
from ..models.users import UpdateUser, User

mongodb_client = mongodb_connect()
router = APIRouter(
    prefix="/users",
    tags=["users"],
    responses={404: {"description": "Not found"}},
)


@router.post("")
async def create_user(request: Request, user: User):
    """Create a new user."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["see"])
        roles = get_roles(auth_token)
        my_user_sub = get_user_sub(auth_token)

        user_cursor = mongodb_client[MONGODB_DATABASE]["users"].find_one(
            {"email": user.email})
        if user_cursor:
            responseObject = {
                "status": "failed",
                "endpoint": "CreateUser",
                "message": f"Erreur, un utilisateur est déjà enregistré avec l'email '{user.email}'",
            }
            return JSONResponse(content=responseObject, status_code=409)

        sub = str(uuid.uuid4())

        user_dict = user.model_dump()
        user_dict["sub"] = sub
        user_dict["active"] = True
        user_dict["verified"] = True
        user_dict["created_by_sub"] = my_user_sub

        salt = bcrypt.gensalt()
        hashed_password = bcrypt.hashpw(user.password.encode("utf8"), salt)
        user_dict["hashed_password"] = hashed_password.decode("utf8")
        user_dict.pop("password")

        mongodb_client[MONGODB_DATABASE]["users"].insert_one(user_dict)
        responseObject = {
            "status": "success",
            "endpoint": "CreateUser",
            "message": "Utilisateur créé avec succès.",
            "sub": sub
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "CreateUser",
            "message": f"Error lors de l'enregistrement de l'utilisateur: {str(e)}"
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.get("")
async def get_user_list(request: Request):
    """Get all users."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["*"])
        my_sub = get_user_sub(auth_token)
        my_roles = get_roles(auth_token)

        if not any(role in my_roles for role in ["root", "see"]):
            my_sector = mongodb_client[MONGODB_DATABASE]["users"].find_one(
                {"sub": my_sub},
                {"_id": 0, "sector": 1}
            )
            users = mongodb_client[MONGODB_DATABASE]["users"].find(
                {"login": {"$ne": "root"}, "sub": {"$ne": my_sub}, "sector": my_sector["sector"], "active": True},
                {"_id": 0, "hashed_password": 0}
            )
        else:
            users = mongodb_client[MONGODB_DATABASE]["users"].find(
                {"login": {"$ne": "root"}, "sub": {"$ne": my_sub}, "active": True},
                {"_id": 0, "hashed_password": 0}
            )

        responseObject = {
            "status": "success",
            "endpoint": "GetUserList",
            "message": "Liste d'utilisateurs récupéré avec succès",
            "content": list(users)
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "GetUserList",
            "message": f"Error lors de la récupération des utilisateurs: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.get("/{sub}")
async def get_user(request: Request, sub: str):
    """Get a user by his sub."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["*"])
        user = mongodb_client[MONGODB_DATABASE]["users"].find_one(
            {"sub": sub},
            {"_id": 0, "hashed_password": 0}
        )

        if not user:
            responseObject = {
                "status": "error",
                "endpoint": "GetUser",
                "message": f"Utilisateur '{sub}' n'existe pas",
            }
            return JSONResponse(content=responseObject, status_code=404)

        responseObject = {
            "status": "success",
            "endpoint": "GetUser",
            "message": f"Utilisateur '{sub}' récupéré avec succès",
            "content": user
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "GetUser",
            "message": f"Error lors de la récupération de l'utilisateur: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.patch("/{sub}")
async def update_user(request: Request, sub: str, user: UpdateUser):
    """update a user by his sub."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["*"])
        user_cursor = mongodb_client[MONGODB_DATABASE]["users"].find_one(
            {"sub": sub},
            {"_id": 0}
        )

        user_dict = user.model_dump()
        if "photo" in user_dict and user_dict["photo"] == None:
            user_dict["photo"] = ""

        user_dict = {key: value for key,
                     value in user_dict.items() if value is not None}
        
        salt = bcrypt.gensalt()
        if "password" in user_dict:
            hashed_password = bcrypt.hashpw(user.password.encode("utf8"), salt)
            user_dict["hashed_password"] = hashed_password.decode("utf8")
            user_dict.pop("password")

        if not user_cursor:
            responseObject = {
                "status": "error",
                "endpoint": "UpdateUser",
                "message": f"Utilisateur '{sub}' n'existe pas",
            }
            return JSONResponse(content=responseObject, status_code=404)

        mongodb_client[MONGODB_DATABASE]["users"].update_one(
            {"sub": sub},
            {"$set": user_dict}
        )

        responseObject = {
            "status": "success",
            "endpoint": "UpdateUser",
            "message": f"Utilisateur '{sub}' mis à jour avec succès",
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "UpdateUser",
            "message": f"Error lors de la récupération de l'utilisateur: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.delete("/{sub}")
async def disable_user(request: Request, sub: str):
    """Disable a user by his sub."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["see"])
        result = mongodb_client[MONGODB_DATABASE]["users"].find_one_and_update(
            {"sub": sub, "active": True}, {"$set": {"active": False}}
        )

        if not result:
            responseObject = {
                "status": "error",
                "endpoint": "DisableUser",
                "message": f"Vous n'avez pas le droit d'accès à cette ressource",
            }
            return JSONResponse(content=responseObject, status_code=403)

        responseObject = {
            "status": "success",
            "endpoint": "DisableUser",
            "message": f"Utilisateur '{sub}' désactivé avec succès",
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "DisableUser",
            "message": f"Error lors de la désactivation de l'utilisateur: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.put("/{sub}")
async def activate_user(request: Request, sub: str):
    """Activate a user by his sub."""
    try:
        auth_token = request.headers["authorization"].replace("Bearer ", "")
        check_access(auth_token, ["see"])
        result = mongodb_client[MONGODB_DATABASE]["users"].find_one_and_update(
            {"sub": sub, "active": False}, {"$set": {"active": True}}
        )

        if not result:
            responseObject = {
                "status": "error",
                "endpoint": "ActivateUser",
                "message": f"Vous n'avez pas le droit d'accès à cette ressource",
            }
            return JSONResponse(content=responseObject, status_code=403)

        responseObject = {
            "status": "success",
            "endpoint": "ActivateUser",
            "message": f"Utilisateur '{sub}' activé avec succès",
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "ActivateUser",
            "message": f"Error lors de l'activation de l'utilisateur: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.get("/role/{role}")
async def get_users_by_role(request: Request, role: str):
    """Get all users filtered by a role."""
    auth_token = request.headers["authorization"].replace("Bearer ", "")
    check_access(auth_token, ["*"])
    roles = role.split("-")
    try:
        users = mongodb_client[MONGODB_DATABASE]["users"].find(
            {"roles": {"$in": roles}, "active": True}, {"_id": 0})
        responseObject = {
            "status": "success",
            "endpoint": "GetUserListByRole",
            "message": f"Liste d'utilisateurs ayant le role '{role}' récupéré avec succès",
            "content": list(users)
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "GetUserListByRole",
            "message": f"Error lors de la récupération des utilisateurs: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)


@router.get("/archive/list")
async def get_archived_users(request: Request):
    """Get all archived users."""
    auth_token = request.headers["authorization"].replace("Bearer ", "")
    check_access(auth_token, ["*"])
    my_sub = get_user_sub(auth_token)
    my_roles = get_roles(auth_token)
    try:
        if not any(role in my_roles for role in ["root", "see"]):
            my_sector = mongodb_client[MONGODB_DATABASE]["users"].find_one(
                {"sub": my_sub},
                {"_id": 0, "sector": 1}
            )
            users = mongodb_client[MONGODB_DATABASE]["users"].find(
                {"login": {"$ne": "root"}, "sub": {"$ne": my_sub}, "sector": my_sector["sector"], "active": False},
                {"_id": 0, "hashed_password": 0}
            )
        else:
            users = mongodb_client[MONGODB_DATABASE]["users"].find(
                {"login": {"$ne": "root"}, "sub": {"$ne": my_sub}, "active": False},
                {"_id": 0, "hashed_password": 0}
            )

        responseObject = {
            "status": "success",
            "endpoint": "GetArchivedUserList",
            "message": f"Liste d'utilisateurs archivés récupéré avec succès",
            "content": list(users)
        }
        return JSONResponse(content=responseObject, status_code=200)
    except Exception as e:
        responseObject = {
            "status": "error",
            "endpoint": "GetArchivedUserList",
            "message": f"Error lors de la récupération des utilisateurs: {str(e)}",
        }
        return JSONResponse(content=responseObject, status_code=500)
