from datetime import datetime, timedelta, timezone

from pymongo.errors import CollectionInvalid

from .save_data import _to_utc_datetime


COMAP_COLLECTION_SUFFIX = "generador_comap_timeseries"

# Ventana de busqueda del ultimo snapshot, igual criterio que
# get_last_state_bulk(): acota el escaneo de la time-series y evita revivir
# lecturas antiguas de un centro que ya no esta enviando datos.
COMAP_LATEST_WINDOW_DAYS = 7


def get_comap_collection_name(centro_id):
    """Construye el nombre de la colección COMAP dedicada al centro."""
    _, _, centro = centro_id.split("-")
    return f"{centro}_{COMAP_COLLECTION_SUFFIX}"


def _ensure_comap_collection(db, collection_name):
    """Crea la time-series COMAP si todavía no existe."""
    if collection_name not in db.list_collection_names():
        try:
            collection = db.create_collection(
                collection_name,
                timeseries={
                    "timeField": "timestamp",
                    "metaField": "comap_id",
                    "granularity": "minutes",
                },
            )
            try:
                collection.create_index(
                    [("comap_id", 1), ("timestamp", -1)],
                    name="idx_comap_latest",
                )
            except Exception as e:
                print(
                    f"No fue posible crear índice COMAP en {collection_name} "
                    f"linea {e.__traceback__.tb_lineno}: {e}"
                )
        except CollectionInvalid:
            # Otro worker de Apache pudo crear la colección entre la consulta y
            # create_collection(). En ese caso basta con reutilizarla.
            pass

    return db[collection_name]


def save_comap_data(db, centro_id, generators_comap):
    """
    Guarda un documento por generador y recepción en la time-series del centro.

    No deduplica: si el centro reenvía una medición, se conserva nuevamente.
    La fecha visible se mantiene en ``timestamp_str`` y ``timestamp`` contiene
    el BSON Date UTC requerido por MongoDB time-series.
    """
    try:
        if not generators_comap or not isinstance(generators_comap, dict):
            print(f"Sin bloque COMAP válido para {centro_id}")
            return 0

        generators = generators_comap.get("generators")
        if not isinstance(generators, dict) or not generators:
            print(f"Sin generadores COMAP para {centro_id}")
            return 0

        collection_name = get_comap_collection_name(centro_id)
        documents = []

        for generator_name, generator_data in generators.items():
            if not generator_data or not isinstance(generator_data, dict):
                print(
                    f"Generador COMAP vacío o inválido {generator_name} "
                    f"para {centro_id}"
                )
                continue

            received_timestamp = generator_data.get("timestamp")
            if not received_timestamp:
                print(
                    f"Generador COMAP {generator_name} sin timestamp "
                    f"para {centro_id}"
                )
                continue

            try:
                timestamp_utc = _to_utc_datetime(received_timestamp)
            except Exception as e:
                print(
                    f"Timestamp COMAP inválido para {centro_id}/{generator_name} "
                    f"linea {e.__traceback__.tb_lineno}: {e}"
                )
                continue

            timestamp_str = (
                received_timestamp.isoformat()
                if hasattr(received_timestamp, "isoformat")
                else str(received_timestamp)
            )
            document = dict(generator_data)
            document.update(
                {
                    "timestamp": timestamp_utc,
                    "timestamp_str": timestamp_str,
                    "centro_id": centro_id,
                    "generador_name": generator_name,
                    "comap_id": f"{centro_id}-{generator_name}",
                }
            )
            documents.append(document)

        if not documents:
            return 0

        collection = _ensure_comap_collection(db, collection_name)
        collection.insert_many(documents, ordered=False)
        print(
            f"Guardados {len(documents)} documentos COMAP en {collection_name} "
            f"para {centro_id}"
        )
        return len(documents)

    except Exception as e:
        print(f"Error en save_comap_data linea {e.__traceback__.tb_lineno}: {e}")
        return 0


def get_latest_comap_timestamp(generators_comap):
    """Devuelve el timestamp mas reciente del bloque COMAP, o None.

    Un centro COMAP puro no tiene modulos ni bombas, asi que la hora del
    endpoint no puede salir de ahi: se toma del ultimo snapshot del generador.
    """
    if not isinstance(generators_comap, dict):
        return None

    generators = generators_comap.get("generators")
    if not isinstance(generators, dict):
        return None

    timestamps = [
        data.get("timestamp")
        for data in generators.values()
        if isinstance(data, dict) and isinstance(data.get("timestamp"), str)
    ]

    return max(timestamps) if timestamps else None


def get_latest_comap_data(db, centro_id):
    """Devuelve el último snapshot de cada generador con el contrato del emisor."""
    response = {"generators": {}}

    try:
        collection_name = get_comap_collection_name(centro_id)
        if collection_name not in db.list_collection_names():
            return response

        fecha_limite = datetime.now(timezone.utc) - timedelta(
            days=COMAP_LATEST_WINDOW_DAYS
        )

        pipeline = [
            {"$match": {"timestamp": {"$gte": fecha_limite}}},
            {"$sort": {"comap_id": 1, "timestamp": -1}},
            {
                "$group": {
                    "_id": "$generador_name",
                    "snapshot": {"$first": "$$ROOT"},
                }
            },
        ]

        for result in db[collection_name].aggregate(pipeline, allowDiskUse=True):
            generator_name = result.get("_id")
            snapshot = result.get("snapshot")
            if not generator_name or not isinstance(snapshot, dict):
                continue

            generator_data = dict(snapshot)
            original_timestamp = generator_data.pop("timestamp_str", None)
            generator_data.pop("_id", None)
            generator_data.pop("timestamp", None)
            generator_data.pop("centro_id", None)
            generator_data.pop("generador_name", None)
            generator_data.pop("comap_id", None)

            if original_timestamp is not None:
                generator_data["timestamp"] = original_timestamp

            response["generators"][generator_name] = generator_data

    except Exception as e:
        print(f"Error en get_latest_comap_data linea {e.__traceback__.tb_lineno}: {e}")

    return response
