"""MongoDB adapter for db-test-helpers."""

from __future__ import annotations

import re
from datetime import UTC, datetime
from typing import Any

_ISO8601_PATTERN = re.compile(
    r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$"
)


class MongoAdapter:
    """DatabaseAdapter for MongoDB via pymongo.

    Args:
        db: A ``pymongo.database.Database`` instance.
    """

    def __init__(self, db: Any) -> None:
        self._db = db

    def clear_group(self, group: str, parent_path: str) -> None:
        col_path = f"{parent_path}/{group}" if parent_path else group
        self._db[col_path].delete_many({})

    def write_record(self, group: str, parent_path: str, data: dict[str, Any]) -> dict[str, Any]:
        col_path = f"{parent_path}/{group}" if parent_path else group
        data = dict(data)
        doc_id = data.pop("__document_id__", None)
        data = _to_mongo_types(data)
        if doc_id is not None:
            data["_id"] = doc_id
        self._db[col_path].insert_one(data)
        result_id = str(data.pop("_id"))
        return {"__document_id__": result_id, **data}

    def read_records(self, group: str, parent_path: str) -> list[dict[str, Any]]:
        col_path = f"{parent_path}/{group}" if parent_path else group
        docs = list(self._db[col_path].find())
        return [{"__document_id__": str(d.pop("_id")), **_from_mongo_types(d)} for d in docs]

    def build_child_path(self, parent_path: str, group: str, record: dict[str, Any]) -> str:
        col_path = f"{parent_path}/{group}" if parent_path else group
        return f"{col_path}/{record['__document_id__']}"


def _to_mongo_types(data: Any) -> Any:
    if isinstance(data, dict):
        return {k: _to_mongo_types(v) for k, v in data.items()}
    if isinstance(data, list):
        return [_to_mongo_types(item) for item in data]
    if isinstance(data, str) and _ISO8601_PATTERN.match(data):
        return datetime.fromisoformat(data.replace("Z", "+00:00"))
    return data


def _from_mongo_types(data: Any) -> Any:
    if isinstance(data, dict):
        return {k: _from_mongo_types(v) for k, v in data.items()}
    if isinstance(data, list):
        return [_from_mongo_types(item) for item in data]
    if isinstance(data, datetime):
        # pymongo returns naive datetimes in UTC by default (tz_aware=False)
        if data.tzinfo is None:
            data = data.replace(tzinfo=UTC)
        return data.astimezone(UTC).isoformat().replace("+00:00", "Z")
    return data
