import logging
from typing import Dict

from pymongo import MongoClient


class MongoConnect:
    def __init__(self, uri):
        try:
            self.uri = uri
            self.client = MongoClient(self.uri, connect=False)
        except Exception as e:
            logging.error(f"Exception in connection {(str(e))}")
            raise e

    def __call__(self, *args, **kwargs):
        return self.client

    def __repr__(self):
        return f"Mongo Client(uri:{self.uri}, server_info={self.client.server_info()})"


class MongoCollectionBaseClass:
    def __init__(self, mongo_client, database, collection):
        self.client = mongo_client
        self.database = database
        self.collection = collection

    def __repr__(self):
        return f"{self.__class__.__name__}(database={self.database},collection={self.collection})"

    def insert_one(self, data: Dict):

        try:
            database_name = self.database
            collection_name = self.collection
            db = self.client[database_name]
            collection = db[collection_name]
            response = collection.insert_one(data)
            return response.inserted_id
        except Exception as e:
            logging.error(f"Error in inserting the data {str(e)}")
            raise e

    def find_one(self, query, filter_dict=None):
        try:
            database_name = self.client[self.database]
            collection_name = database_name[self.collection]
            if not filter_dict:
                filter_dict = {"_id": 0}
            response = collection_name.find_one(query, filter_dict)
            return response
        except Exception as e:
            logging.error(f"Failed to fetch {str(e)}")
            raise e

    def update_one(self, query: Dict, data: Dict, upsert: bool = False ):

        try:
            database_name = self.database
            collection_name = self.collection
            db = self.client[database_name]
            collection = db[collection_name]
            response = collection.update_one(query, {"$set": data}, upsert=upsert)
            return response.modified_count
        except Exception as e:
            logging.error(f"Failed to update one doc {str(e)}")
            raise e

    def delete_one(self, query: Dict):

        try:
            database_name = self.database
            collection_name = self.collection
            db = self.client[database_name]
            collection = db[collection_name]
            response = collection.delete_one(query)
            return response.deleted_count
        except Exception as e:
            logging.error(f"Failed to delete {str(e)}")
            raise e
