"""API Flask para buscar y devolver documentos en MongoDB.

Este servicio expone un endpoint `/search` que permite buscar documentos en una colección
específica usando un filtro JSON.

Uso:
  python app.py
  curl "http://localhost:5000/search?collection=miColeccion&filter={\"activo\":true}"

La URI de MongoDB se configura en el archivo `config.py`.
"""

from __future__ import annotations

import json
import logging
from typing import Any

from flask import Flask, jsonify, request
from pymongo import MongoClient

import config

if not config.MONGODB_URI:
    raise SystemExit(
        "ERROR: Debes configurar MONGODB_URI en config.py o en la variable de entorno MONGODB_URI."
    )

logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s")

app = Flask(__name__)

# Cliente global para reutilizar la conexión entre peticiones
client: MongoClient | None = None


def get_db():
    global client
    if client is None:
        client = MongoClient(config.MONGODB_URI)
        logging.info("Conectado a MongoDB")

    if config.MONGODB_DB:
        return client[config.MONGODB_DB]

    return client.get_default_database()


@app.route("/search")
def search():
    collection_name = request.args.get("collection") or config.MONGODB_COLLECTION
    filter_str = request.args.get("filter")
    limit_str = request.args.get("limit")

    if not collection_name:
        return jsonify({"error": "Parámetro 'collection' requerido (o config.MONGODB_COLLECTION)."}), 400

    mongo_filter: dict[str, Any] = {}
    if filter_str:
        try:
            mongo_filter = json.loads(filter_str)
        except json.JSONDecodeError as exc:
            return (
                jsonify({
                    "error": "No se pudo parsear el parámetro 'filter'. Debe ser JSON válido.",
                    "details": str(exc),
                }),
                400,
            )

    limit = None
    if limit_str:
        try:
            limit = max(1, min(1000, int(limit_str)))
        except ValueError:
            return jsonify({"error": "El parámetro 'limit' debe ser un número entero."}), 400

    db = get_db()
    cursor = db[collection_name].find(mongo_filter)
    if limit is not None:
        cursor = cursor.limit(limit)

    documents = list(cursor)

    # Convertir ObjectId y otros tipos a strings usando json.dumps() indirectamente.
    def _serialize(obj: Any) -> Any:
        try:
            return json.loads(json.dumps(obj, default=str))
        except TypeError:
            return str(obj)

    serialized = [_serialize(doc) for doc in documents]

    return jsonify({"count": len(serialized), "documents": serialized})


@app.route("/")
def root():
    return (
        "<h1>Mongo Search App (Python)</h1>"
        "<p>Usa <code>/search?collection=...&filter=...&limit=...</code></p>"
        "<p>O configura <code>MONGODB_COLLECTION</code> en <code>config.py</code> para no tener que pasar <code>collection</code> en cada petición.</p>"
    )


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
