"""
Generic MongoDB client & helpers for CuCu backend.

Đây là nơi dùng chung cho:
- Core memos logic (memos, attachments, inbox, user_settings...)
- Conversation history của chatbot
"""

from __future__ import annotations

import logging
import os
from datetime import datetime, timezone
from typing import Any

from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase

logger = logging.getLogger(__name__)

# MongoDB Configuration
MONGODB_URI = os.getenv(
    "MONGODB_URI",
    "mongodb+srv://20010841:vuhoanganh1704@cluster0.h6qro.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0",
)
MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME", "cucu_note")

# Collection names với prefix cuccu_
COLLECTION_MEMOS = "cuccu_memos"
COLLECTION_ATTACHMENTS = "cuccu_attachments"
COLLECTION_MEMO_RELATIONS = "cuccu_memo_relations"
COLLECTION_REACTIONS = "cuccu_reactions"
COLLECTION_MEMO_EMBEDDINGS = "cuccu_memo_embeddings"
COLLECTION_INBOX = "cuccu_inbox"
COLLECTION_USER_SETTINGS = "cuccu_user_settings"


class MongoDBClient:
    """Singleton MongoDB client cho toàn backend CuCu."""

    _instance: "MongoDBClient | None" = None
    _client: AsyncIOMotorClient | None = None
    _db: AsyncIOMotorDatabase | None = None

    def __new__(cls) -> "MongoDBClient":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    async def connect(self) -> None:
        """Initialize MongoDB connection."""
        if self._client is None:
            try:
                self._client = AsyncIOMotorClient(MONGODB_URI)
                self._db = self._client[MONGODB_DB_NAME]
                await self._client.admin.command("ping")
                logger.info("✅ Connected to MongoDB: %s", MONGODB_DB_NAME)
            except Exception as e:  # pragma: no cover - startup failure
                logger.error("❌ MongoDB connection failed: %s", e)
                raise

    async def close(self) -> None:
        """Close MongoDB connection."""
        if self._client:
            self._client.close()
            self._client = None
            self._db = None
            logger.info("MongoDB connection closed")

    @property
    def db(self) -> AsyncIOMotorDatabase:
        if self._db is None:
            raise RuntimeError("MongoDB not connected. Call connect() first.")
        return self._db

    # Collection helpers (không bắt buộc dùng, nhưng tiện)
    @property
    def memos(self):
        return self.db[COLLECTION_MEMOS]

    @property
    def attachments(self):
        return self.db[COLLECTION_ATTACHMENTS]

    @property
    def memo_relations(self):
        return self.db[COLLECTION_MEMO_RELATIONS]

    @property
    def reactions(self):
        return self.db[COLLECTION_REACTIONS]

    @property
    def memo_embeddings(self):
        return self.db[COLLECTION_MEMO_EMBEDDINGS]

    @property
    def inbox(self):
        return self.db[COLLECTION_INBOX]

    @property
    def user_settings(self):
        return self.db[COLLECTION_USER_SETTINGS]


# Singleton instance
mongodb_client = MongoDBClient()


def generate_uid() -> str:
    """Generate a unique ID for memos (similar to nanoid)."""
    import secrets

    return secrets.token_urlsafe(16)[:22]


def utc_now() -> datetime:
    """Get current UTC time."""
    return datetime.now(timezone.utc)


def serialize_doc(doc: dict[str, Any]) -> dict[str, Any] | None:
    """Convert MongoDB document to JSON-serializable dict."""
    if doc is None:
        return None
    result = dict(doc)
    if "_id" in result:
        result["_id"] = str(result["_id"])
    for key, value in result.items():
        if isinstance(value, datetime):
            result[key] = value.isoformat()
    return result


def parse_object_id(id_str: str) -> ObjectId | None:
    """Parse string to ObjectId, return None if invalid."""
    try:
        return ObjectId(id_str)
    except Exception:
        return None


async def init_mongodb():
    """Call on app startup."""
    await mongodb_client.connect()


async def close_mongodb():
    """Call on app shutdown."""
    await mongodb_client.close()


