from motor.motor_asyncio import AsyncIOMotorClient
from app.core.config import settings
import logging
import asyncio

# Fallback for when MongoDB is not available
class MockCollection:
    def __init__(self, data=None):
        self._data = data or {}
    async def find_one(self, query): return None
    async def insert_one(self, doc): return doc
    async def update_one(self, query, update, upsert=False): return None
    async def count_documents(self, query): return 0
    def find(self, query=None): return self
    def sort(self, *args): return self
    def limit(self, n): return self
    async def to_list(self, length): return []
    def aggregate(self, pipeline): return self

class MockDB:
    def __getattr__(self, name): return MockCollection()

class Database:
    client: AsyncIOMotorClient = None
    db = None
    is_mock: bool = False

db_connection = Database()

async def get_db():
    return db_connection.db

async def connect_to_mongo():
    try:
        db_connection.client = AsyncIOMotorClient(
            settings.MONGO_URL,
            serverSelectionTimeoutMS=2000,
            maxPoolSize=100,
            minPoolSize=10
        )
        await db_connection.client.admin.command('ping')
        db_connection.db = db_connection.client[settings.DB_NAME]
        db_connection.is_mock = False
        logging.info(f"Connected to MongoDB at {settings.MONGO_URL}")
    except Exception as e:
        logging.warning(f"Failed to connect to MongoDB: {e}. Falling back to MOCK database.")
        try:
            import mongomock
            from unittest.mock import MagicMock
            # Very simple async wrapper for mongomock
            class AsyncMockCollection:
                def __init__(self, coll): self.coll = coll
                async def find_one(self, *args, **kwargs): return self.coll.find_one(*args, **kwargs)
                async def insert_one(self, *args, **kwargs): return self.coll.insert_one(*args, **kwargs)
                async def update_one(self, *args, **kwargs): return self.coll.update_one(*args, **kwargs)
                async def count_documents(self, *args, **kwargs): return self.coll.count_documents(*args, **kwargs)
                def find(self, *args, **kwargs): 
                    res = self.coll.find(*args, **kwargs)
                    return MagicMock(to_list=lambda length: asyncio.sleep(0, list(res)), sort=lambda *a: res, limit=lambda *a: res)
                def aggregate(self, pipeline):
                    res = self.coll.aggregate(pipeline)
                    return MagicMock(to_list=lambda length: asyncio.sleep(0, list(res)))

            class AsyncMockDB:
                def __init__(self): self.client = mongomock.MongoClient()
                def __getitem__(self, name): return AsyncMockCollection(self.client[settings.DB_NAME][name])
                def __getattr__(self, name): return self.__getitem__(name)

            db_connection.db = AsyncMockDB()
            db_connection.is_mock = True
        except ImportError:
            db_connection.db = MockDB()
            db_connection.is_mock = True

async def close_mongo_connection():
    if db_connection.client:
        db_connection.client.close()
