from __future__ import annotations

import sys
from collections.abc import Callable, Iterable
from dataclasses import dataclass
from typing import Any

from app.core.mongo_runtime import clear_mongo_runtime, init_mongo_runtime


PROTECTED_COLLECTIONS = frozenset({"users", "schema_migrations"})
CONFIRMATION_TEXT = "VACIAR"


@dataclass(frozen=True)
class CollectionPurgeResult:
    name: str
    deleted_count: int


@dataclass(frozen=True)
class PurgeSummary:
    database_name: str
    protected_collections: tuple[str, ...]
    purged_collections: tuple[CollectionPurgeResult, ...]

    @property
    def total_deleted(self) -> int:
        return sum(item.deleted_count for item in self.purged_collections)


def get_target_collection_names(
    collection_names: Iterable[str],
    *,
    protected_collections: Iterable[str] = PROTECTED_COLLECTIONS,
) -> list[str]:
    protected = set(protected_collections)
    return sorted(name for name in collection_names if name not in protected)


def confirm_purge(
    *,
    database_name: str,
    protected_collections: Iterable[str] = PROTECTED_COLLECTIONS,
    input_fn: Callable[[str], str] = input,
    output_fn: Callable[[str], None] = print,
) -> bool:
    protected_list = ", ".join(sorted(protected_collections))
    output_fn(f"Base objetivo: {database_name}")
    output_fn(f"Colecciones protegidas: {protected_list}")
    output_fn(f"Escribe {CONFIRMATION_TEXT!r} para continuar.")
    response = input_fn("> ").strip()
    return response == CONFIRMATION_TEXT


def purge_database(
    database: Any,
    *,
    database_name: str,
    protected_collections: Iterable[str] = PROTECTED_COLLECTIONS,
) -> PurgeSummary:
    target_names = get_target_collection_names(
        database.list_collection_names(),
        protected_collections=protected_collections,
    )
    results: list[CollectionPurgeResult] = []
    for collection_name in target_names:
        result = database[collection_name].delete_many({})
        deleted_count = int(getattr(result, "deleted_count", 0) or 0)
        results.append(CollectionPurgeResult(name=collection_name, deleted_count=deleted_count))
    return PurgeSummary(
        database_name=database_name,
        protected_collections=tuple(sorted(protected_collections)),
        purged_collections=tuple(results),
    )


def print_summary(summary: PurgeSummary, *, output_fn: Callable[[str], None] = print) -> None:
    output_fn(f"Base afectada: {summary.database_name}")
    output_fn(f"Colecciones protegidas: {', '.join(summary.protected_collections)}")
    if summary.purged_collections:
        output_fn("Colecciones vaciadas:")
        for item in summary.purged_collections:
            output_fn(f"- {item.name}: {item.deleted_count} documentos eliminados")
    else:
        output_fn("No había colecciones elegibles para vaciar.")
    output_fn(f"Total eliminado: {summary.total_deleted}")


def main() -> int:
    runtime = init_mongo_runtime()
    try:
        database = runtime.sync_database
        database_name = str(getattr(database, "name", "") or "(sin nombre)")

        if not sys.stdin.isatty():
            print("Cancelado: la confirmación requiere una terminal interactiva.")
            return 1

        confirmed = confirm_purge(database_name=database_name)
        if not confirmed:
            print("Operación cancelada. No se eliminaron documentos.")
            return 0

        summary = purge_database(database, database_name=database_name)
        print_summary(summary)
        return 0
    finally:
        clear_mongo_runtime(runtime)


if __name__ == "__main__":
    raise SystemExit(main())
