from typing import Optional
from bson import ObjectId
from app.models.entities import UserEntity


class UserRepository:
    def __init__(self, db):
        self.collection = db.users

    def get_all_users(self) -> list[UserEntity]:
        """Retrieve all users from the database."""
        users = list(self.collection.find({}, {"_id": 0}))
        return [UserEntity(**user) for user in users]

    def get_user_by_email(self, email: str) -> Optional[UserEntity]:
        """Retrieve a user based on their email address."""
        user = self.collection.find_one({"email": email})
        return UserEntity(**user) if user else None

    def get_user_by_id(self, user_id: str) -> Optional[UserEntity]:
        """Retrieve a user based on their ID."""
        object_id = ObjectId(user_id)
        user = self.collection.find_one({"_id": object_id})
        return UserEntity(**user) if user else None

    def get_by_google_id(self, google_id: str) -> Optional[UserEntity]:
        """Retrieve a user based on their Google ID."""
        user_data = self.collection.find_one({"google_id": google_id})
        return UserEntity(**user_data) if user_data else None

    def insert_user(self, user_data: UserEntity) -> str:
        """Insert a new user into the database and return the user's ID."""
        result = self.collection.insert_one(user_data.model_dump())
        return str(result.inserted_id)

    def update_user(self, user_id: str, update_data: dict) -> bool:
        """Update all fields of a user based on their ID."""
        object_id = ObjectId(user_id)
        result = self.collection.update_one({"_id": object_id}, {"$set": update_data})
        return result.modified_count > 0

    def update_user_field(self, user_id: str, field: str, value) -> bool:
        """Update a single field of a user based on their ID."""
        object_id = ObjectId(user_id)
        result = self.collection.update_one(
            {"_id": object_id}, {"$set": {field: value}}
        )
        return result.modified_count > 0

    def delete_user(self, user_id: str) -> bool:
        """Delete a user based on their ID."""
        object_id = ObjectId(user_id)
        result = self.collection.delete_one({"_id": object_id})
        return result.deleted_count > 0
